-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Pie and Combined(bar + line) chart in HealthFragment
- Add menu(in toolbar) in HealthFragment for changing chart type - Add Pie chart for KCal, Time and Distance in HealthFragment - Add Combined chart for KCal, Time and Distance in HealthFragment
- Loading branch information
1 parent
3bf7051
commit 2ad6b2b
Showing
22 changed files
with
1,248 additions
and
160 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
app/src/main/java/com/example/cyclofit/ui/adapter/CombinedChartAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.example.cyclofit.ui.adapter | ||
|
||
import androidx.fragment.app.Fragment | ||
import androidx.fragment.app.FragmentManager | ||
import androidx.lifecycle.Lifecycle | ||
import com.example.cyclofit.ui.fragment.DistanceCombineChartFragment | ||
import com.example.cyclofit.ui.fragment.KcalCombinedChartFragment | ||
import com.example.cyclofit.ui.fragment.TimeCombinedChartFragment | ||
|
||
class CombinedChartAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : | ||
LineChartAdapter(fragmentManager, lifecycle) { | ||
|
||
override fun createFragment(position: Int): Fragment { | ||
return when (position) { | ||
0 -> KcalCombinedChartFragment() | ||
1 -> TimeCombinedChartFragment() | ||
else -> DistanceCombineChartFragment() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
app/src/main/java/com/example/cyclofit/ui/adapter/PieChartAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.example.cyclofit.ui.adapter | ||
|
||
import androidx.fragment.app.Fragment | ||
import androidx.fragment.app.FragmentManager | ||
import androidx.lifecycle.Lifecycle | ||
import com.example.cyclofit.ui.fragment.DistancePieChartFragment | ||
import com.example.cyclofit.ui.fragment.KcalPeiChartFragment | ||
import com.example.cyclofit.ui.fragment.TimePieCharFragment | ||
|
||
class PieChartAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : | ||
LineChartAdapter(fragmentManager, lifecycle) { | ||
|
||
override fun createFragment(position: Int): Fragment { | ||
return when (position) { | ||
0 -> KcalPeiChartFragment() | ||
1 -> TimePieCharFragment() | ||
else -> DistancePieChartFragment() | ||
} | ||
} | ||
} |
156 changes: 156 additions & 0 deletions
156
app/src/main/java/com/example/cyclofit/ui/fragment/DistanceCombineChartFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package com.example.cyclofit.ui.fragment | ||
|
||
import android.content.Context | ||
import android.graphics.Color | ||
import android.graphics.Typeface | ||
import android.os.Bundle | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import androidx.core.content.res.ResourcesCompat | ||
import androidx.fragment.app.Fragment | ||
import com.example.cyclofit.R | ||
import com.example.cyclofit.databinding.FragmentDistanceCombineChartBinding | ||
import com.example.cyclofit.model.Shared | ||
import com.example.cyclofit.ui.utils.Constants | ||
import com.example.cyclofit.ui.utils.Months | ||
import com.github.mikephil.charting.charts.CombinedChart | ||
import com.github.mikephil.charting.components.AxisBase | ||
import com.github.mikephil.charting.components.Legend | ||
import com.github.mikephil.charting.components.XAxis | ||
import com.github.mikephil.charting.components.YAxis | ||
import com.github.mikephil.charting.data.BarData | ||
import com.github.mikephil.charting.data.BarDataSet | ||
import com.github.mikephil.charting.data.BarEntry | ||
import com.github.mikephil.charting.data.CombinedData | ||
import com.github.mikephil.charting.data.Entry | ||
import com.github.mikephil.charting.data.LineData | ||
import com.github.mikephil.charting.data.LineDataSet | ||
import com.github.mikephil.charting.formatter.ValueFormatter | ||
import com.google.gson.Gson | ||
import com.google.gson.reflect.TypeToken | ||
import java.lang.reflect.Type | ||
|
||
class DistanceCombineChartFragment : Fragment() { | ||
lateinit var binding: FragmentDistanceCombineChartBinding | ||
var sp = ArrayList<Shared>() | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, container: ViewGroup?, | ||
savedInstanceState: Bundle? | ||
): View { | ||
binding = FragmentDistanceCombineChartBinding.inflate(inflater, container, false) | ||
val sharedPreferences1 = requireContext().getSharedPreferences( | ||
Constants.CYCLOFIT_PREFERENCES, | ||
Context.MODE_PRIVATE | ||
) | ||
val gson = Gson() | ||
val json = sharedPreferences1.getString("timer", null) | ||
val type: Type = object : TypeToken<ArrayList<Shared?>?>() {}.type | ||
|
||
if (json != null) { | ||
sp = gson.fromJson(json, type) | ||
} | ||
|
||
val distanceArrayList = ArrayList<String>() | ||
for (i in 0 until sp.size) { | ||
distanceArrayList.add("0") | ||
} | ||
val lineDataList = mutableListOf<Entry>() | ||
val barDataList = mutableListOf<BarEntry>() | ||
for ((x, i) in distanceArrayList.withIndex()) { | ||
lineDataList.add(Entry(x.toFloat(), i.toFloat())) | ||
barDataList.add(BarEntry(x.toFloat(), i.toFloat())) | ||
} | ||
val combinedData = CombinedData().apply { | ||
setData(generateLineData(lineDataList)) | ||
setData(generateBarData(barDataList)) | ||
setValueTypeface(Typeface.DEFAULT) | ||
} | ||
setCombinedChart(combinedData) | ||
return binding.root | ||
} | ||
|
||
private fun setCombinedChart(combinedData: CombinedData) { | ||
binding.combinedChart.apply { | ||
data = combinedData | ||
invalidate() | ||
description.isEnabled = false | ||
setBackgroundColor(Color.TRANSPARENT) | ||
setDrawGridBackground(false) | ||
setDrawBarShadow(false) | ||
isHighlightFullBarEnabled = false | ||
// draw bars behind lines | ||
drawOrder = arrayOf( | ||
CombinedChart.DrawOrder.BAR, | ||
CombinedChart.DrawOrder.BUBBLE, | ||
CombinedChart.DrawOrder.CANDLE, | ||
CombinedChart.DrawOrder.LINE, | ||
CombinedChart.DrawOrder.SCATTER | ||
) | ||
legend.apply { | ||
isWordWrapEnabled = true | ||
verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM | ||
horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER | ||
orientation = Legend.LegendOrientation.HORIZONTAL | ||
setDrawInside(false) | ||
} | ||
customizeYAxis(axisRight) | ||
customizeYAxis(axisLeft) | ||
val formatter = object : ValueFormatter() { | ||
override fun getAxisLabel(value: Float, axis: AxisBase?): String { | ||
val index = value.toInt() % Months.values().size | ||
return Months.values()[index].name | ||
} | ||
} | ||
xAxis.apply { | ||
setDrawGridLines(false) | ||
setDrawAxisLine(false) | ||
position = XAxis.XAxisPosition.BOTTOM | ||
axisMinimum = 0f - 0.25f | ||
granularity = 1f | ||
valueFormatter = formatter | ||
axisMaximum = combinedData.xMax + 0.25f | ||
} | ||
} | ||
} | ||
|
||
private fun customizeYAxis(axis: YAxis) { | ||
axis.apply { | ||
setDrawGridLines(false) | ||
setDrawAxisLine(false) | ||
setDrawLabels(false) | ||
axisMinimum = 0f | ||
} | ||
} | ||
|
||
private fun generateLineData(dataList: MutableList<Entry>): LineData { | ||
val lineData = LineData() | ||
val lineDataSet = LineDataSet(dataList, "Line DataSet") | ||
lineDataSet.apply { | ||
color = resources.getColor(R.color.purple_200, resources.newTheme()) | ||
valueTextSize = 12f | ||
valueTextColor = Color.BLACK | ||
setDrawValues(true) | ||
mode = LineDataSet.Mode.CUBIC_BEZIER | ||
lineWidth = 2f | ||
axisDependency = YAxis.AxisDependency.LEFT | ||
} | ||
lineData.addDataSet(lineDataSet) | ||
return lineData | ||
} | ||
|
||
private fun generateBarData(dataList: MutableList<BarEntry>): BarData { | ||
val dataSet = BarDataSet(dataList, "Bar") | ||
dataSet.apply { | ||
color = ResourcesCompat.getColor(resources, R.color.light_green, resources.newTheme()) | ||
valueTextColor = Color.TRANSPARENT | ||
dataSet.valueTextSize = 10f | ||
axisDependency = YAxis.AxisDependency.LEFT | ||
} | ||
val barWidth = 0.45f | ||
val barData = BarData(dataSet) | ||
barData.barWidth = barWidth | ||
return barData | ||
} | ||
} |
124 changes: 124 additions & 0 deletions
124
app/src/main/java/com/example/cyclofit/ui/fragment/DistancePieChartFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package com.example.cyclofit.ui.fragment | ||
|
||
import android.content.Context | ||
import android.graphics.Color | ||
import android.graphics.Typeface | ||
import android.os.Bundle | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import androidx.fragment.app.Fragment | ||
import com.example.cyclofit.databinding.FragmentDistancePieChartBinding | ||
import com.example.cyclofit.model.Shared | ||
import com.example.cyclofit.ui.utils.ChartUtils | ||
import com.example.cyclofit.ui.utils.Constants | ||
import com.github.mikephil.charting.animation.Easing | ||
import com.github.mikephil.charting.components.Legend | ||
import com.github.mikephil.charting.data.Entry | ||
import com.github.mikephil.charting.data.PieData | ||
import com.github.mikephil.charting.data.PieDataSet | ||
import com.github.mikephil.charting.data.PieEntry | ||
import com.github.mikephil.charting.formatter.ValueFormatter | ||
import com.github.mikephil.charting.highlight.Highlight | ||
import com.github.mikephil.charting.listener.OnChartValueSelectedListener | ||
import com.github.mikephil.charting.utils.MPPointF | ||
import com.google.gson.Gson | ||
import com.google.gson.reflect.TypeToken | ||
import java.lang.reflect.Type | ||
|
||
class DistancePieChartFragment : Fragment(), OnChartValueSelectedListener { | ||
lateinit var binding: FragmentDistancePieChartBinding | ||
var sp = ArrayList<Shared>() | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, container: ViewGroup?, | ||
savedInstanceState: Bundle? | ||
): View { | ||
binding = FragmentDistancePieChartBinding.inflate(inflater, container, false) | ||
val sharedPreferences1 = requireContext().getSharedPreferences( | ||
Constants.CYCLOFIT_PREFERENCES, | ||
Context.MODE_PRIVATE | ||
) | ||
val gson = Gson() | ||
val json = sharedPreferences1.getString("timer", null) | ||
val type: Type = object : TypeToken<ArrayList<Shared?>?>() {}.type | ||
|
||
if (json != null) { | ||
sp = gson.fromJson(json, type) | ||
} | ||
|
||
val distanceArrayList = ArrayList<String>() | ||
for (i in 0 until sp.size) { | ||
distanceArrayList.add("0") | ||
} | ||
val pieDataList = mutableListOf<PieEntry>() | ||
for ((x, i) in distanceArrayList.withIndex()) { | ||
pieDataList.add(PieEntry(i.toFloat(), "${i.toFloat()} km")) | ||
} | ||
setPieChart(pieDataList) | ||
return binding.root | ||
} | ||
|
||
private fun setPieChart(dataList: MutableList<PieEntry>) { | ||
val dataSet = PieDataSet(dataList, "My Graph") | ||
dataSet.apply { | ||
valueTextSize = 16f | ||
valueTextColor = Color.BLACK | ||
setDrawIcons(false) | ||
sliceSpace = 3f | ||
iconsOffset = MPPointF(0f, 40f) | ||
selectionShift = 5f | ||
colors = ChartUtils.colors | ||
} | ||
|
||
binding.pieChart.apply { | ||
isDrawHoleEnabled = false | ||
description.isEnabled = false | ||
setUsePercentValues(true) | ||
|
||
// entry label text styling | ||
setEntryLabelColor(Color.TRANSPARENT) // hide label text in Pie chart | ||
setEntryLabelTypeface(Typeface.DEFAULT) | ||
setEntryLabelTextSize(16f) | ||
|
||
dragDecelerationFrictionCoef = 0.95f | ||
rotationAngle = 0f | ||
// enable rotation of the chart by touch | ||
isRotationEnabled = true | ||
isHighlightPerTapEnabled = true | ||
|
||
animateY(1400, Easing.EaseInOutQuad) | ||
|
||
legend.apply { | ||
verticalAlignment = Legend.LegendVerticalAlignment.TOP | ||
horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT | ||
orientation = Legend.LegendOrientation.VERTICAL | ||
setDrawInside(false) | ||
xEntrySpace = 7f | ||
yEntrySpace = 0f | ||
yOffset = 0f | ||
} | ||
val pieData = PieData(dataSet).apply { | ||
setValueFormatter(object : ValueFormatter() { | ||
override fun getPieLabel(value: Float, pieEntry: PieEntry?): String { | ||
return "${String.format("%.1f", value)} %" | ||
} | ||
}) | ||
} | ||
data = PieData(dataSet) | ||
highlightValues(null) // undo all highlights | ||
invalidate() | ||
} | ||
// add a selection listener | ||
binding.pieChart.setOnChartValueSelectedListener(this) | ||
} | ||
|
||
override fun onValueSelected(e: Entry?, h: Highlight?) { | ||
if (e == null) | ||
return | ||
} | ||
|
||
override fun onNothingSelected() { | ||
return | ||
} | ||
} |
Oops, something went wrong.