From 3df75415056ecfefc26d7d223f1fc4af27ac3c9c Mon Sep 17 00:00:00 2001
From: Avior
Date: Thu, 16 Feb 2023 10:07:41 +0100
Subject: [PATCH] feat: Make sample more customizable (#43)
---
README.md | 2 +-
build.gradle.kts | 3 +
.../main/java/com/dzeio/charts/ChartView.kt | 12 +-
.../main/java/com/dzeio/charts/axis/XAxis.kt | 15 +-
.../main/java/com/dzeio/charts/axis/YAxis.kt | 2 +-
.../com/dzeio/charts/components/Annotation.kt | 5 +
.../com/dzeio/charts/series/BarSerie.kt.old | 160 ----------
sample/build.gradle.kts | 23 +-
sample/src/main/AndroidManifest.xml | 4 +-
.../com/dzeio/chartsapp/ui/ChartFragment.kt | 178 ++++++++++++
.../com/dzeio/chartsapp/ui/MainActivity.kt | 97 +++++++
.../com/dzeio/chartsapp/ui/MainFragment.kt | 93 ++++++
.../dzeio/chartsapp/utils/MaterialUtils.kt | 57 ++++
.../java/com/dzeio/chartsapp/utils/Utils.kt | 19 ++
.../com/dzeio/chartstest/ui/MainActivity.kt | 19 --
.../com/dzeio/chartstest/ui/MainFragment.kt | 273 ------------------
.../src/main/res/drawable/shape_divider.xml | 6 -
sample/src/main/res/layout/activity_main.xml | 55 +++-
sample/src/main/res/layout/fragment_chart.xml | 216 ++++++++++++++
sample/src/main/res/layout/fragment_main.xml | 46 +--
sample/src/main/res/navigation/nav_graph.xml | 27 +-
.../res/values/ic_launcher_background.xml | 4 -
sample/src/main/res/values/strings.xml | 3 -
sample/src/main/res/values/themes.xml | 10 +-
24 files changed, 798 insertions(+), 531 deletions(-)
delete mode 100644 library/src/main/java/com/dzeio/charts/series/BarSerie.kt.old
create mode 100644 sample/src/main/java/com/dzeio/chartsapp/ui/ChartFragment.kt
create mode 100644 sample/src/main/java/com/dzeio/chartsapp/ui/MainActivity.kt
create mode 100644 sample/src/main/java/com/dzeio/chartsapp/ui/MainFragment.kt
create mode 100644 sample/src/main/java/com/dzeio/chartsapp/utils/MaterialUtils.kt
create mode 100644 sample/src/main/java/com/dzeio/chartsapp/utils/Utils.kt
delete mode 100644 sample/src/main/java/com/dzeio/chartstest/ui/MainActivity.kt
delete mode 100644 sample/src/main/java/com/dzeio/chartstest/ui/MainFragment.kt
delete mode 100644 sample/src/main/res/drawable/shape_divider.xml
create mode 100644 sample/src/main/res/layout/fragment_chart.xml
delete mode 100644 sample/src/main/res/values/ic_launcher_background.xml
delete mode 100644 sample/src/main/res/values/strings.xml
diff --git a/README.md b/README.md
index 62cdde4..a3cfed8 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@ chart.refresh()
-_note: Every charts used above used a helper function to have Material 3 colors [See MainFragment.kt the materialTheme function](./sample/src/main/java/com/dzeio/chartstest/ui/MainFragment.kt)_
+_note: Every charts used above used a helper function to have Material 3 colors [See the MaterialUtils.kt class](sample/src/main/java/com/dzeio/chartsapp/utils/MaterialUtils.kt)_
## Build
diff --git a/build.gradle.kts b/build.gradle.kts
index 5652e57..5628f89 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,6 +5,9 @@ buildscript {
}
dependencies {
classpath("com.android.tools.build:gradle:7.4.1")
+
+ // Safe Navigation
+ classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.5.3")
}
}
diff --git a/library/src/main/java/com/dzeio/charts/ChartView.kt b/library/src/main/java/com/dzeio/charts/ChartView.kt
index 910f657..99ccb35 100644
--- a/library/src/main/java/com/dzeio/charts/ChartView.kt
+++ b/library/src/main/java/com/dzeio/charts/ChartView.kt
@@ -22,7 +22,7 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet
View(context, attrs), ChartViewInterface {
private companion object {
- const val TAG = "Charts/ChartView"
+ const val TAG = "ChartView"
}
override val animator: Animation = Animation()
@@ -97,6 +97,10 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet
refresh()
}
+ setOnToggleScroll {
+ // note: true == no scroll
+ parent?.requestDisallowInterceptTouchEvent(!it && (yAxis.scrollEnabled || xAxis.scrollEnabled))
+ }
setOnChartClick { x, y ->
if (getDataset().isEmpty()) {
return@setOnChartClick
@@ -161,15 +165,11 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet
// invalidate the view
invalidate()
-// removeCallbacks(animator)
-// post(animator)
}
- private var lastRun = runUpdates
-
override fun onDraw(canvas: Canvas) {
// don't draw anything if everything is empty
- if (!runUpdates && lastRun == runUpdates && series.isEmpty() || series.maxOf { it.entries.size } == 0) {
+ if (!runUpdates || series.isEmpty() || series.maxOf { it.entries.size } == 0) {
super.onDraw(canvas)
return
}
diff --git a/library/src/main/java/com/dzeio/charts/axis/XAxis.kt b/library/src/main/java/com/dzeio/charts/axis/XAxis.kt
index 07406f8..7cf7da5 100644
--- a/library/src/main/java/com/dzeio/charts/axis/XAxis.kt
+++ b/library/src/main/java/com/dzeio/charts/axis/XAxis.kt
@@ -92,18 +92,14 @@ class XAxis(
var maxHeight = 0f
- val graphIncrement = space.width() / (labelCount - 1)
- val valueIncrement = getDataWidth() / (labelCount - 1)
+ val valueIncrement = getDataWidth() / (labelCount - 1).coerceAtLeast(1)
for (index in 0 until labelCount) {
val text = onValueFormat(x + valueIncrement * index)
textPaint.getTextBounds(text, 0, text.length, rect)
+ getPositionOnRect(valueIncrement, space)
maxHeight = maxHeight.coerceAtLeast(rect.height().toFloat() + 1)
- var xPos = space.left + graphIncrement * index
-
- if (xPos + rect.width() > space.right) {
- xPos = space.right - rect.width()
- }
+ val xPos = getPositionOnRect(x + valueIncrement * index, space).toFloat()
canvas.drawText(
text,
@@ -134,8 +130,8 @@ class XAxis(
.coerceIn(1.0, drawableSpace.width().toDouble())
// handle grouped series
- if (view.type == ChartType.GROUPED) {
- return result / view.series.size - spacing / 2 * (view.series.size - 1)
+ if (view.type == ChartType.GROUPED && view.series.size > 1) {
+ return ((result - (spacing / 2 * view.series.size)) / view.series.size).coerceAtLeast(1.0)
}
return result
@@ -145,5 +141,4 @@ class XAxis(
// TODO: handle the auto dataWidth better (still not sure it is good enough)
return dataWidth ?: (getXMax() - getXMin() + 1)
}
-
}
diff --git a/library/src/main/java/com/dzeio/charts/axis/YAxis.kt b/library/src/main/java/com/dzeio/charts/axis/YAxis.kt
index bba96a3..95f07bf 100644
--- a/library/src/main/java/com/dzeio/charts/axis/YAxis.kt
+++ b/library/src/main/java/com/dzeio/charts/axis/YAxis.kt
@@ -162,7 +162,7 @@ class YAxis(
val max = getYMax() - min
var maxWidth = 0f
- val valueIncrement = max / (labelCount - 1)
+ val valueIncrement = max / (labelCount - 1).coerceAtLeast(1)
for (index in 0 until labelCount) {
val value = min + (valueIncrement * index)
diff --git a/library/src/main/java/com/dzeio/charts/components/Annotation.kt b/library/src/main/java/com/dzeio/charts/components/Annotation.kt
index 84b55e7..6a1262b 100644
--- a/library/src/main/java/com/dzeio/charts/components/Annotation.kt
+++ b/library/src/main/java/com/dzeio/charts/components/Annotation.kt
@@ -73,6 +73,11 @@ class Annotation(
val xCenter = view.xAxis.getEntryWidth(space) / 2.0 + x
+ if (xCenter < space.left || xCenter > space.right) {
+ entry = null
+ return
+ }
+
val xText = annotationSubTitleFormat.invoke(entry!!)
val yText = annotationTitleFormat.invoke(entry!!)
diff --git a/library/src/main/java/com/dzeio/charts/series/BarSerie.kt.old b/library/src/main/java/com/dzeio/charts/series/BarSerie.kt.old
deleted file mode 100644
index b6205e0..0000000
--- a/library/src/main/java/com/dzeio/charts/series/BarSerie.kt.old
+++ /dev/null
@@ -1,160 +0,0 @@
-package com.dzeio.charts.series
-
-import android.graphics.Canvas
-import android.graphics.Paint
-import android.graphics.Rect
-import android.graphics.RectF
-import android.util.Log
-import kotlin.math.max
-
-class BarSerie : SerieAbstract() {
-
- companion object {
- const val TAG = "DzeioCharts/BarSerie"
- }
-
- var spacing: Float = 8f
-
- /**
- * Values displayed on the grapd
- */
- var displayedDatas = arrayListOf()
-
- /**
- * Target values
- */
- var targetDatas = arrayListOf()
-
- var targetPercentList = arrayListOf()
- var percentList = arrayListOf()
-
- var previousRefresh = 0
-
- private var fgPaint: Paint = Paint().apply {
- isAntiAlias = true
- }
-
- private val r = Rect()
-
- override fun onUpdate(): Boolean {
- var needNewFrame = false
- for (i in targetPercentList.indices) {
- val value = view.animation.updateValue(
- 1f,
- targetPercentList[i],
- percentList[i],
- 0f,
- 0.00f
- )
-
- if (value != percentList[i]) {
- needNewFrame = true
- percentList[i] = value
- }
- }
- return needNewFrame
- }
-
- override fun prepareData() {
- val max: Float = if (view.yAxis.max != null) view.yAxis.max!! else {
- getYMax(true)
- }
-
- targetPercentList = arrayListOf()
-
-// Log.d(TAG, "offset: ${view.getXOffset()}, displayed: ${view.getDisplayedEntries()}")
- for (item in getDisplayedEntries()) {
-// // // Process bottom texts
-// val text = view.xAxis.onValueFormat(item.x)
-// bottomTexts.add(text)
-//
-// // get Text boundaries
-// view.xAxis.labels.build().getTextBounds(text, 0, text.length, r)
-//
-// // get height of text
-// if (bottomTextHeight < r.height()) {
-// bottomTextHeight = r.height()
-// }
-//
-// // get text descent
-// val descent = abs(r.bottom)
-// if (bottomTextDescent < descent) {
-// bottomTextDescent = descent
-// }
-
- // process values
-// Log.d(TAG, item.y.toString())
-
- // add to animations the values
- targetPercentList.add(1 - item.y / max)
- }
-
- // post list
- val offset = view.getXOffset()
- val movement = offset - previousRefresh
- Log.d(TAG, "$offset - $previousRefresh = $movement")
- if (movement != 0) {
- previousRefresh = offset
- }
-// if (movement != 0) {
-// Log.d(TAG, movement.toString())
-// }
- if (movement >= 1) {
- percentList = percentList.subList(1, percentList.size).toCollection(ArrayList())
- percentList.add(1f)
- } else if (movement <= -1) {
- percentList = percentList.subList(0, percentList.size - 1).toCollection(ArrayList())
- percentList.add(0, 1f)
- }
-
- if (percentList.isEmpty() || percentList.size < targetPercentList.size) {
- val temp = targetPercentList.size - percentList.size
- for (i in 0 until temp) {
- percentList.add(1f)
- }
- } else if (percentList.size > targetPercentList.size) {
- val temp = percentList.size - targetPercentList.size
- for (i in 0 until temp) {
- percentList.removeAt(percentList.size - 1)
- }
- }
-
- fgPaint.color = view.yAxis.color
- }
-
- override fun displayData(canvas: Canvas, rect: RectF) {
- val barWidth = (rect.width() - view.padding * 2) / view.getDisplayedEntries() - spacing
-
- if (percentList.isNotEmpty()) {
- // draw each rectangles
- for (i in 1..percentList.size) {
-// Log.d(TAG, percentList[i - 1].toString())
- val left = rect.left + spacing * i + barWidth * (i - 1).toFloat() + view.padding
-// Log.d(TAG, "$spacing, $i, $barWidth = $left")
- val right = rect.left + (spacing + barWidth) * i.toFloat()
- val bottom = rect.top + rect.height() - view.padding
- val top = (bottom - rect.top) * percentList[i - 1] + view.padding
-
- // create rounded rect
- canvas.drawRoundRect(left, top, right, bottom, 8f, 8f, fgPaint)
- // remove the bottom corners DUH
- canvas.drawRect(left, max(top, bottom - 8f), right, bottom, fgPaint)
- val targetTop = (bottom - rect.top) * targetPercentList[i - 1]
-
- val text = view.yAxis.onValueFormat(getYMax(true) - getYMax(true) * targetPercentList[i - 1], true)
- view.xAxis.labels.build().getTextBounds(text, 0, text.length, r)
- val doDisplayIn =
- r.width() + 10f < barWidth && bottom - targetTop > r.height() + 40f
- if (view.debug || !doDisplayIn || (doDisplayIn && bottom - top > r.height() + 40f)) {
- val y = if (doDisplayIn) top + r.height() + 20f else top - r.height()
- canvas.drawText(
- text,
- left + (right - left) / 2,
- y,
- view.xAxis.labels.build()
- )
- }
- }
- }
- }
-}
diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts
index 20bf19c..579121e 100644
--- a/sample/build.gradle.kts
+++ b/sample/build.gradle.kts
@@ -1,14 +1,23 @@
plugins {
+ // Android Application?
id("com.android.application")
+
+ // Support for kotlin in Android
kotlin("android")
+
+ // Safe Navigation
+ id("androidx.navigation.safeargs")
+
+ // keep at bottom
+ kotlin("kapt")
}
android {
- namespace = "com.dzeio.chartstest"
+ namespace = "com.dzeio.chartsapp"
compileSdk = 33
defaultConfig {
- applicationId = "com.dzeio.chartstest"
+ applicationId = "com.dzeio.chartsapp"
minSdk = 21
targetSdk = 33
versionCode = 1
@@ -31,19 +40,21 @@ android {
kotlinOptions {
jvmTarget = "11"
}
-
+
buildFeatures {
viewBinding = true
+ dataBinding = true
}
}
dependencies {
implementation(project(":library"))
-
+
// Material Design
- implementation("com.google.android.material:material:1.7.0")
+ implementation("com.google.android.material:material:1.8.0")
// Navigation because I don't want to maintain basic transactions and shit
implementation("androidx.navigation:navigation-fragment-ktx:2.5.3")
-}
\ No newline at end of file
+ implementation("androidx.navigation:navigation-ui-ktx:2.5.3")
+}
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
index 1b3c192..d9982ea 100644
--- a/sample/src/main/AndroidManifest.xml
+++ b/sample/src/main/AndroidManifest.xml
@@ -3,7 +3,7 @@
-
\ No newline at end of file
+
diff --git a/sample/src/main/java/com/dzeio/chartsapp/ui/ChartFragment.kt b/sample/src/main/java/com/dzeio/chartsapp/ui/ChartFragment.kt
new file mode 100644
index 0000000..35164e7
--- /dev/null
+++ b/sample/src/main/java/com/dzeio/chartsapp/ui/ChartFragment.kt
@@ -0,0 +1,178 @@
+package com.dzeio.chartsapp.ui
+
+import android.graphics.Color
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.navArgs
+import com.dzeio.charts.ChartType
+import com.dzeio.charts.ChartViewInterface
+import com.dzeio.charts.Entry
+import com.dzeio.charts.series.BarSerie
+import com.dzeio.charts.series.LineSerie
+import com.dzeio.charts.series.SerieInterface
+import com.dzeio.chartsapp.databinding.FragmentChartBinding
+import com.dzeio.chartsapp.utils.MaterialUtils
+import com.dzeio.chartsapp.utils.Utils
+import kotlin.math.roundToInt
+import kotlin.random.Random
+
+class ChartFragment : Fragment() {
+ private var _binding: FragmentChartBinding? = null
+
+ private val args: ChartFragmentArgs by navArgs()
+
+ private var numberOfValues = 5
+
+ private lateinit var chart: ChartViewInterface
+ private val binding: FragmentChartBinding get() = _binding!!
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ _binding = FragmentChartBinding.inflate(inflater, container, false)
+
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ chart = binding.chart
+ addSerie()
+
+ MaterialUtils.materielTheme(chart, requireView())
+
+ chart.refresh()
+
+ binding.addValue.setOnClickListener {
+ chart.series.forEach {
+ it.entries.add(
+ Entry(
+ it.entries.size.toDouble(),
+ Random.nextInt(0, 100).toFloat()
+ )
+ )
+ }
+ numberOfValues++
+ chart.refresh()
+ }
+
+ binding.removeValue.setOnClickListener {
+ chart.series.forEach {
+ it.entries.removeLastOrNull()
+ }
+ numberOfValues--
+ chart.refresh()
+ }
+
+ binding.addSerie.setOnClickListener {
+ addSerie()
+ chart.refresh()
+ }
+
+ binding.removeSerie.setOnClickListener {
+ chart.series.removeLastOrNull()
+ chart.refresh()
+ }
+
+ binding.switchSubtype.setOnClickListener {
+ when (chart.type) {
+ ChartType.BASIC -> {
+ chart.type = ChartType.GROUPED
+ binding.switchSubtype.setText("Grouped Chart")
+ }
+ ChartType.GROUPED -> {
+ chart.type = ChartType.STACKED
+ binding.switchSubtype.setText("Stacked Chart")
+ }
+ else -> {
+ chart.type = ChartType.BASIC
+ binding.switchSubtype.setText("Basic Chart")
+ }
+ }
+ chart.refresh()
+ }
+
+ binding.switchAnimations.setOnCheckedChangeListener { _, isChecked ->
+ chart.animator.enabled = isChecked
+ }
+
+ binding.switchXAxis.setOnCheckedChangeListener { _, isChecked ->
+ chart.xAxis.enabled = isChecked
+ chart.refresh()
+ }
+
+ binding.switchYAxis.setOnCheckedChangeListener { _, isChecked ->
+ chart.yAxis.enabled = isChecked
+ chart.refresh()
+ }
+
+ binding.sliderXAxis.addOnChangeListener { _, value, _ ->
+ chart.xAxis.labelCount = value.roundToInt()
+ chart.refresh()
+ }
+
+ binding.sliderYAxis.addOnChangeListener { _, value, _ ->
+ chart.yAxis.labelCount = value.roundToInt()
+ chart.refresh()
+ }
+
+ binding.switchXAxisScrollable.setOnCheckedChangeListener { _, isChecked ->
+ chart.xAxis.scrollEnabled = isChecked
+ if (isChecked) {
+ chart.xAxis.dataWidth = binding.sliderXAxisScroll.value.toDouble()
+ binding.sliderXAxisScroll.visibility = View.VISIBLE
+ } else {
+ chart.xAxis.dataWidth = null
+ chart.xAxis.x = 0.0
+ binding.sliderXAxisScroll.visibility = View.GONE
+ }
+ chart.refresh()
+ }
+
+ binding.sliderXAxisScroll.visibility = View.GONE
+ binding.sliderXAxisScroll.addOnChangeListener { _, value, _ ->
+ if (chart.xAxis.dataWidth != null) {
+ chart.xAxis.dataWidth = value.toDouble()
+ chart.refresh()
+ }
+ }
+ }
+
+ private var lastGenerated = 0
+ private fun addSerie(): SerieInterface {
+ val toGet = if (args.chartType == null) {
+ if (lastGenerated == 0) {
+ "barchart"
+ } else {
+ "linechart"
+ }
+ } else {
+ args.chartType
+ }
+ if (lastGenerated++ >= 1) {
+ lastGenerated = 0
+ }
+ val serie = if (toGet === "barchart") {
+ BarSerie(chart).apply {
+ barPaint.color = randomColor()
+ }
+ } else {
+ LineSerie(chart).apply {
+ linePaint.color = randomColor()
+ }
+ }
+ serie.entries = Utils.generateRandomDataset(numberOfValues)
+ return serie
+ }
+
+ private fun randomColor(): Int {
+ return Color.argb(
+ 255,
+ Random.nextInt(),
+ Random.nextInt(),
+ Random.nextInt()
+ )
+ }
+}
diff --git a/sample/src/main/java/com/dzeio/chartsapp/ui/MainActivity.kt b/sample/src/main/java/com/dzeio/chartsapp/ui/MainActivity.kt
new file mode 100644
index 0000000..c6a7473
--- /dev/null
+++ b/sample/src/main/java/com/dzeio/chartsapp/ui/MainActivity.kt
@@ -0,0 +1,97 @@
+package com.dzeio.chartsapp.ui
+
+import android.content.res.Configuration
+import android.os.Build
+import android.os.Bundle
+import android.view.WindowManager
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.WindowCompat
+import androidx.core.view.updatePadding
+import androidx.navigation.NavController
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.AppBarConfiguration
+import androidx.navigation.ui.navigateUp
+import androidx.navigation.ui.setupActionBarWithNavController
+import com.dzeio.chartsapp.R
+import com.dzeio.chartsapp.databinding.ActivityMainBinding
+
+class MainActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityMainBinding
+
+ private lateinit var appBarConfiguration: AppBarConfiguration
+
+ private lateinit var navController: NavController
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ setSupportActionBar(binding.toolbar)
+
+ // Comportement chelou API 28-
+ // Comportement normal 31+
+
+ // do not do the cool status/navigation bars for API 29 & 30
+ if (Build.VERSION.SDK_INT != Build.VERSION_CODES.R && Build.VERSION.SDK_INT != Build.VERSION_CODES.Q) {
+ // allow to put the content behind the status bar & Navigation bar (one of them at least lul)
+ // ALSO: make the status/navigation bars semi-transparent
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
+
+ // Make the color of the navigation bar semi-transparent
+// window.navigationBarColor = Color.TRANSPARENT
+ // Make the color of the status bar transparent
+// window.statusBarColor = Color.TRANSPARENT
+ // Apply the previous changes
+// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+
+ // Update toolbar height with the statusbar size included
+ // ALSO: make both the status/navigation bars transparent (WHYYYYYYY)
+ val toolbarHeight = binding.toolbar.layoutParams.height
+ window.decorView.setOnApplyWindowInsetsListener { _, insets ->
+ val statusBarSize = insets.systemWindowInsetTop
+ // Add padding to the toolbar (YaY I know how something works)
+ binding.toolbar.updatePadding(top = statusBarSize)
+ binding.toolbar.layoutParams.height = toolbarHeight + statusBarSize
+ return@setOnApplyWindowInsetsListener insets
+ }
+
+ // normally makes sure icons are at the correct color but idk if it works
+ when (this.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK)) {
+ Configuration.UI_MODE_NIGHT_YES -> {
+ WindowCompat.getInsetsController(window, window.decorView).apply {
+ // force to display the bars in light color
+ isAppearanceLightNavigationBars = true
+ isAppearanceLightStatusBars = false // WHY
+ }
+ }
+ Configuration.UI_MODE_NIGHT_NO, Configuration.UI_MODE_NIGHT_UNDEFINED -> {
+ WindowCompat.getInsetsController(window, window.decorView).apply {
+ // force to display the bars in dark color
+ isAppearanceLightNavigationBars = false
+ isAppearanceLightStatusBars = true // WHY
+ }
+ }
+ }
+ }
+
+ val navHostFragment =
+ supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
+
+ navController = navHostFragment.navController
+
+ appBarConfiguration = AppBarConfiguration(
+ setOf(
+ R.id.main_fragment
+ )
+ )
+
+ setupActionBarWithNavController(navController, appBarConfiguration)
+ }
+
+ override fun onSupportNavigateUp(): Boolean =
+ navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
+}
diff --git a/sample/src/main/java/com/dzeio/chartsapp/ui/MainFragment.kt b/sample/src/main/java/com/dzeio/chartsapp/ui/MainFragment.kt
new file mode 100644
index 0000000..3590d22
--- /dev/null
+++ b/sample/src/main/java/com/dzeio/chartsapp/ui/MainFragment.kt
@@ -0,0 +1,93 @@
+package com.dzeio.chartsapp.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import com.dzeio.charts.series.BarSerie
+import com.dzeio.charts.series.LineSerie
+import com.dzeio.chartsapp.databinding.FragmentMainBinding
+import com.dzeio.chartsapp.utils.MaterialUtils
+import com.dzeio.chartsapp.utils.Utils
+
+class MainFragment : Fragment() {
+ private var _binding: FragmentMainBinding? = null
+ private val binding get() = _binding!!
+
+ private val months = arrayListOf(
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ )
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentMainBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.gotoBarchart.setOnClickListener {
+ findNavController().navigate(
+ MainFragmentDirections.actionMainFragmentToChartFragment("barchart")
+ )
+ }
+
+ binding.gotoLinechart.setOnClickListener {
+ findNavController().navigate(
+ MainFragmentDirections.actionMainFragmentToChartFragment("linechart")
+ )
+ }
+
+ binding.gotoBarLineChart.setOnClickListener {
+ findNavController().navigate(
+ MainFragmentDirections.actionMainFragmentToChartFragment(null)
+ )
+ }
+
+ binding.barchart.apply {
+ BarSerie(this).apply {
+ entries = Utils.generateRandomDataset(5)
+ }
+ MaterialUtils.materielTheme(this, requireView())
+ }
+
+ binding.linechart.apply {
+ LineSerie(this).apply {
+ entries = Utils.generateRandomDataset(5)
+ }
+ MaterialUtils.materielTheme(this, requireView())
+ }
+
+ binding.bothchart.apply {
+ BarSerie(this).apply {
+ entries = Utils.generateRandomDataset(5)
+ }
+ LineSerie(this).apply {
+ entries = Utils.generateRandomDataset(5)
+ }
+ MaterialUtils.materielTheme(this, requireView())
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/sample/src/main/java/com/dzeio/chartsapp/utils/MaterialUtils.kt b/sample/src/main/java/com/dzeio/chartsapp/utils/MaterialUtils.kt
new file mode 100644
index 0000000..346b9c1
--- /dev/null
+++ b/sample/src/main/java/com/dzeio/chartsapp/utils/MaterialUtils.kt
@@ -0,0 +1,57 @@
+package com.dzeio.chartsapp.utils
+
+import android.view.View
+import com.dzeio.charts.ChartViewInterface
+import com.dzeio.charts.series.BarSerie
+import com.dzeio.charts.series.LineSerie
+import com.google.android.material.color.MaterialColors
+
+object MaterialUtils {
+ fun materielTheme(chart: ChartViewInterface, view: View) {
+ chart.yAxis.apply {
+ textLabel.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorOnPrimaryContainer)
+ linePaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorOnPrimaryContainer)
+ goalLinePaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorError)
+ }
+
+ chart.xAxis.textPaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorOnPrimaryContainer)
+ chart.annotator.apply {
+ backgroundPaint.color = MaterialColors.getColor(
+ view,
+ com.google.android.material.R.attr.colorBackgroundFloating
+ )
+ titlePaint.color = MaterialColors.getColor(
+ view,
+ com.google.android.material.R.attr.colorOnPrimaryContainer
+ )
+ subTitlePaint.color = MaterialColors.getColor(
+ view,
+ com.google.android.material.R.attr.colorOnPrimaryContainer
+ )
+ }
+
+ for (serie in chart.series) {
+ if (serie is BarSerie) {
+ serie.apply {
+ barPaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorPrimary)
+ textPaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorOnPrimary)
+ textExternalPaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorPrimary)
+ }
+ } else if (serie is LineSerie) {
+ serie.apply {
+ linePaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorPrimary)
+ textPaint.color =
+ MaterialColors.getColor(view, com.google.android.material.R.attr.colorOnPrimary)
+ }
+ }
+ }
+ }
+}
diff --git a/sample/src/main/java/com/dzeio/chartsapp/utils/Utils.kt b/sample/src/main/java/com/dzeio/chartsapp/utils/Utils.kt
new file mode 100644
index 0000000..9d2bec4
--- /dev/null
+++ b/sample/src/main/java/com/dzeio/chartsapp/utils/Utils.kt
@@ -0,0 +1,19 @@
+package com.dzeio.chartsapp.utils
+
+import com.dzeio.charts.Entry
+import kotlin.random.Random.Default.nextInt
+
+object Utils {
+ fun generateRandomDataset(size: Int = 100, min: Int = 0, max: Int = 100, xStep: Int = 1): ArrayList {
+ val dataset: ArrayList = ArrayList()
+ for (i in 0 until size) {
+ dataset.add(
+ Entry(
+ (i * xStep).toDouble(),
+ nextInt(min, max).toFloat()
+ )
+ )
+ }
+ return dataset
+ }
+}
diff --git a/sample/src/main/java/com/dzeio/chartstest/ui/MainActivity.kt b/sample/src/main/java/com/dzeio/chartstest/ui/MainActivity.kt
deleted file mode 100644
index 583cc93..0000000
--- a/sample/src/main/java/com/dzeio/chartstest/ui/MainActivity.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.dzeio.chartstest.ui
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.WindowCompat
-import com.dzeio.chartstest.databinding.ActivityMainBinding
-
-class MainActivity : AppCompatActivity() {
-
- private lateinit var binding: ActivityMainBinding
-
- override fun onCreate(savedInstanceState: Bundle?) {
- WindowCompat.setDecorFitsSystemWindows(window, false)
- super.onCreate(savedInstanceState)
-
- binding = ActivityMainBinding.inflate(layoutInflater)
- setContentView(binding.root)
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/dzeio/chartstest/ui/MainFragment.kt b/sample/src/main/java/com/dzeio/chartstest/ui/MainFragment.kt
deleted file mode 100644
index 0b02622..0000000
--- a/sample/src/main/java/com/dzeio/chartstest/ui/MainFragment.kt
+++ /dev/null
@@ -1,273 +0,0 @@
-package com.dzeio.chartstest.ui
-
-import android.graphics.Color
-import android.graphics.Paint
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import com.dzeio.charts.ChartType
-import com.dzeio.charts.ChartView
-import com.dzeio.charts.Entry
-import com.dzeio.charts.axis.Line
-import com.dzeio.charts.series.BarSerie
-import com.dzeio.charts.series.LineSerie
-import com.dzeio.chartstest.databinding.FragmentMainBinding
-import com.google.android.material.color.MaterialColors
-import kotlin.math.roundToInt
-import kotlin.random.Random
-
-class MainFragment : Fragment() {
- private var _binding: FragmentMainBinding? = null
- private val binding get() = _binding!!
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- _binding = FragmentMainBinding.inflate(inflater, container, false)
- return binding.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.chartGrouped.apply {
- // setup the Serie
- val serie1 = BarSerie(this)
- val serie2 = BarSerie(this)
-
- animator.duration = 750
-
- // transform the chart into a grouped chart
- type = ChartType.GROUPED
- yAxis.setYMin(0f)
-
- // utils function to use Material3 auto colors
- materielTheme(this, requireView())
- serie2.barPaint.color = Color.RED
-
- // give the serie it's entries
- serie1.entries = generateRandomDataset(5)
- serie2.entries = generateRandomDataset(5)
-
- // refresh the Chart
- refresh()
- }
-
- binding.chartStacked.apply {
- // setup the Serie
- val serie1 = BarSerie(this)
- val serie2 = BarSerie(this)
-
- animator.duration = 750
-
- // transform the chart into a grouped chart
- type = ChartType.STACKED
- yAxis.setYMin(0f)
-
- // utils function to use Material3 auto colors
- materielTheme(this, requireView())
- serie2.barPaint.color = Color.RED
-
- // give the serie it's entries
- serie1.entries = generateRandomDataset(10)
- serie2.entries = generateRandomDataset(10)
-
- // refresh the Chart
- refresh()
- }
-
- binding.chartLine.apply {
- // setup the Serie
- val serie = LineSerie(this)
-
- // utils function to use Material3 auto colors
- materielTheme(this, requireView())
-
- // give the serie its entries
- serie.entries = generateRandomDataset(10)
-
- // refresh the Chart
- refresh()
- }
-
- binding.chartBar.apply {
- // setup the Serie
- val serie = BarSerie(this)
- yAxis.setYMin(0f)
-
- // utils function to use Material3 auto colors
- materielTheme(this, requireView())
-
- // give the serie its entries
- serie.entries = generateRandomDataset(10)
-
- // refresh the Chart
- refresh()
- }
-
- binding.chartCustomization.apply {
- // setup the Series
- val serie1 = BarSerie(this)
- val serie2 = LineSerie(this)
-
- // utils function to use Material3 auto colors
- materielTheme(this, requireView())
-
- // give the series their entries
- serie2.entries = generateRandomDataset(20, -50, 50)
- serie1.entries = generateRandomDataset(20, -50, 50).apply {
- for (idx in 0 until size) {
- val compared = serie2.entries[idx]
- val toCompare = this[idx]
- if (compared.y > toCompare.y) {
- toCompare.color = Color.RED
- } else {
- toCompare.color = Color.GREEN
- }
- }
- }
-
-// serie1.textExternalPaint = Color.WHITE
-
- // make the lineSerie red
- serie2.linePaint.color = Color.WHITE
-
- // strokeWidth also control the points width
- serie2.linePaint.strokeWidth = 10f
-
- yAxis.apply {
- // Enable vertical scrolling
- scrollEnabled = true
-
- // change the number of labels
- labelCount = 11
-
- // change how labels are displayed
- onValueFormat = { "${it.roundToInt()}g" }
-
- // change labels colors
- textLabel.color = Color.WHITE
-
- // change line color
- linePaint.color = Color.WHITE
-
- // Add horizontal Lines
- val paint: Paint = Paint(yAxis.linePaint).apply {
- strokeWidth = 8f
- }
- addLine(10f, Line(true, paint))
- addLine(-10f, Line(true, paint))
-
- // change the min/max high
- setYMin(-20f)
- setYMax(20f)
- }
-
- xAxis.apply {
- // Enable horizontal scrolling
- scrollEnabled = true
-
- // set the width of the datas
- dataWidth = 10.0
-
- // change the number of labels displayed
- labelCount = 5
-
- // change the spacing between values (it can be overriden if size to to small)
- spacing = 8.0
-
- // set the offset in data (use with [dataWidth])
- x = 5.0
- }
-
- // refresh the Chart
- refresh()
- }
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
-
- /**
- * Generate a random dataset
- */
- private fun generateRandomDataset(size: Int = 100, min: Int = 0, max: Int = 100): ArrayList {
- val dataset: ArrayList = arrayListOf()
-
- for (i in 0 until size) {
- dataset.add(
- Entry(
- i.toDouble(),
- Random.nextInt(min, max).toFloat()
- )
- )
- }
-
- return dataset
- }
-
- /**
- * Apply Material3 theme to a [ChartView]
- */
- private fun materielTheme(chart: ChartView, view: View) {
- chart.apply {
- yAxis.apply {
- textLabel.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorOnPrimaryContainer
- )
- linePaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorOnPrimaryContainer
- )
- goalLinePaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorError
- )
- }
-
- xAxis.apply {
- textPaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorOnPrimaryContainer
- )
- }
-
- for (serie in series) {
- if (serie is BarSerie) {
- serie.apply {
- barPaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorPrimary
- )
- textPaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorOnPrimary
- )
- textExternalPaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorPrimary
- )
- }
- } else if (serie is LineSerie) {
- serie.apply {
- linePaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorPrimary
- )
- textPaint.color = MaterialColors.getColor(
- view,
- com.google.android.material.R.attr.colorOnPrimary
- )
- }
- }
- }
- }
- }
-}
diff --git a/sample/src/main/res/drawable/shape_divider.xml b/sample/src/main/res/drawable/shape_divider.xml
deleted file mode 100644
index a7e6373..0000000
--- a/sample/src/main/res/drawable/shape_divider.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
index 084b69a..df288f6 100644
--- a/sample/src/main/res/layout/activity_main.xml
+++ b/sample/src/main/res/layout/activity_main.xml
@@ -1,23 +1,52 @@
-
-
+
+
+ >
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/layout/fragment_chart.xml b/sample/src/main/res/layout/fragment_chart.xml
new file mode 100644
index 0000000..9bf58ff
--- /dev/null
+++ b/sample/src/main/res/layout/fragment_chart.xml
@@ -0,0 +1,216 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/layout/fragment_main.xml b/sample/src/main/res/layout/fragment_main.xml
index d8d6133..ea565e9 100644
--- a/sample/src/main/res/layout/fragment_main.xml
+++ b/sample/src/main/res/layout/fragment_main.xml
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:padding="16dp"
tools:context=".ui.MainFragment">
+ android:layout_height="wrap_content">
+ android:layout_height="100dp" />
+
+
+
+ android:layout_height="100dp" />
+
+
+
+ android:layout_height="100dp" />
-
-
-
+ android:id="@+id/goto_bar_line_chart"
+ android:text="Both barChart & lineChart"
+ android:layout_height="wrap_content"/>
diff --git a/sample/src/main/res/navigation/nav_graph.xml b/sample/src/main/res/navigation/nav_graph.xml
index a2ad66f..3dbe075 100644
--- a/sample/src/main/res/navigation/nav_graph.xml
+++ b/sample/src/main/res/navigation/nav_graph.xml
@@ -3,10 +3,27 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
- app:startDestination="@id/MainFragment">
+ app:startDestination="@id/main_fragment">
-
\ No newline at end of file
+ android:id="@+id/main_fragment"
+ android:name="com.dzeio.chartsapp.ui.MainFragment"
+ android:label="Dzeio Charts Examples"
+ tools:layout="@layout/fragment_main">
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/values/ic_launcher_background.xml b/sample/src/main/res/values/ic_launcher_background.xml
deleted file mode 100644
index c5d5899..0000000
--- a/sample/src/main/res/values/ic_launcher_background.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- #FFFFFF
-
\ No newline at end of file
diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml
deleted file mode 100644
index daccbfd..0000000
--- a/sample/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Dzeio Charts
-
\ No newline at end of file
diff --git a/sample/src/main/res/values/themes.xml b/sample/src/main/res/values/themes.xml
index e46a9bf..2420f9b 100644
--- a/sample/src/main/res/values/themes.xml
+++ b/sample/src/main/res/values/themes.xml
@@ -1,4 +1,6 @@
-
-
-
-
\ No newline at end of file
+
+
+