Skip to content

Commit 46cc8e9

Browse files
authored
Merge pull request #697 from AppDevNext/LineChartComposableSample
Sample for LineChartComposable
2 parents 84ec7a8 + eb19970 commit 46cc8e9

17 files changed

Lines changed: 479 additions & 94 deletions

app/src/androidTest/kotlin/info/appdev/chartexample/StartTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
2727
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
2828
import info.appdev.chartexample.compose.HorizontalBarComposeActivity
2929
import info.appdev.chartexample.compose.HorizontalBarFullComposeActivity
30+
import info.appdev.chartexample.compose.MultiLineComposeActivity
3031
import info.appdev.chartexample.fragments.ViewPagerSimpleChartDemo
3132
import info.appdev.chartexample.notimportant.ContentItem
3233
import info.appdev.chartexample.notimportant.DemoBase
@@ -185,6 +186,16 @@ class StartTest {
185186
optionMenu = "$index->$menuTitle"
186187
Timber.d("Testing Compose menu item: $optionMenu")
187188

189+
// Check if menu item exists first
190+
try {
191+
composeTestRule
192+
.onNodeWithTag("menuItem_$menuTitle")
193+
.assertExists()
194+
} catch (_: AssertionError) {
195+
Timber.e("Menu item '$menuTitle' not found for ${contentClass.simpleName}, skipping")
196+
return@forEach
197+
}
198+
188199
// Click the menu item
189200
composeTestRule
190201
.onNodeWithTag("menuItem_$menuTitle")
@@ -265,6 +276,7 @@ class StartTest {
265276
contentItem.clazz == LineChartTimeActivity::class.java ||
266277
contentItem.clazz == HorizontalBarComposeActivity::class.java ||
267278
contentItem.clazz == HorizontalBarFullComposeActivity::class.java ||
279+
contentItem.clazz == MultiLineComposeActivity::class.java ||
268280
contentItem.clazz == GradientActivity::class.java ||
269281
contentItem.clazz == TimeLineActivity::class.java
270282
) {

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<activity android:name="info.appdev.chartexample.HorizontalBarChartActivity" />
2828
<activity android:name="info.appdev.chartexample.compose.HorizontalBarComposeActivity" />
2929
<activity android:name="info.appdev.chartexample.compose.HorizontalBarFullComposeActivity" />
30+
<activity android:name="info.appdev.chartexample.compose.MultiLineComposeActivity" />
3031
<activity android:name="info.appdev.chartexample.HorizontalBarNegativeChartActivity" />
3132
<activity android:name="info.appdev.chartexample.PieChartActivity" />
3233
<activity android:name="info.appdev.chartexample.PieChartRoundedActivity" />

app/src/main/kotlin/info/appdev/chartexample/compose/HorizontalBarFullComposeActivity.kt

Lines changed: 99 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import androidx.compose.material3.TopAppBar
2424
import androidx.compose.material3.TopAppBarDefaults
2525
import androidx.compose.runtime.Composable
2626
import androidx.compose.runtime.getValue
27+
import androidx.compose.runtime.key
2728
import androidx.compose.runtime.mutableFloatStateOf
2829
import androidx.compose.runtime.mutableStateOf
2930
import androidx.compose.runtime.remember
@@ -66,14 +67,23 @@ class HorizontalBarFullComposeActivity : DemoBaseCompose() {
6667
onSaveToGallery: () -> Unit,
6768
onViewGithub: () -> Unit
6869
) {
70+
// State management
71+
var showValues by remember { mutableStateOf(true) }
72+
var showIcons by remember { mutableStateOf(false) }
73+
var highlightEnabled by remember { mutableStateOf(true) }
74+
var pinchZoomEnabled by remember { mutableStateOf(true) }
75+
var autoScaleMinMaxEnabled by remember { mutableStateOf(false) }
76+
var barBordersEnabled by remember { mutableStateOf(false) }
77+
var animationTrigger by remember { mutableStateOf(0) }
78+
6979
var showMenu by remember { mutableStateOf(false) }
7080
var seekBarXValue by remember { mutableFloatStateOf(12f) }
7181
var seekBarYValue by remember { mutableFloatStateOf(50f) }
7282

7383
Scaffold(
7484
topBar = {
7585
TopAppBar(
76-
title = { Text(this.javaClass.simpleName.replace("Activity", "")) },
86+
title = { Text("HorizontalBarFullCompose") },
7787
colors = TopAppBarDefaults.topAppBarColors(
7888
containerColor = MaterialTheme.colorScheme.primary,
7989
titleContentColor = MaterialTheme.colorScheme.onPrimary
@@ -107,71 +117,71 @@ class HorizontalBarFullComposeActivity : DemoBaseCompose() {
107117
text = { Text("Toggle Values") },
108118
onClick = {
109119
showMenu = false
110-
toggleValues()
120+
showValues = !showValues
111121
},
112122
modifier = Modifier.testTag("menuItem_Toggle Values")
113123
)
114124
DropdownMenuItem(
115125
text = { Text("Toggle Icons") },
116126
onClick = {
117127
showMenu = false
118-
toggleIcons()
128+
showIcons = !showIcons
119129
},
120130
modifier = Modifier.testTag("menuItem_Toggle Icons")
121131
)
122132
DropdownMenuItem(
123133
text = { Text("Toggle Highlight") },
124134
onClick = {
125135
showMenu = false
126-
toggleHighlight()
136+
highlightEnabled = !highlightEnabled
127137
},
128138
modifier = Modifier.testTag("menuItem_Toggle Highlight")
129139
)
130140
DropdownMenuItem(
131141
text = { Text("Toggle Pinch Zoom") },
132142
onClick = {
133143
showMenu = false
134-
togglePinchZoom()
144+
pinchZoomEnabled = !pinchZoomEnabled
135145
},
136146
modifier = Modifier.testTag("menuItem_Toggle Pinch Zoom")
137147
)
138148
DropdownMenuItem(
139149
text = { Text("Toggle Auto Scale MinMax") },
140150
onClick = {
141151
showMenu = false
142-
toggleAutoScaleMinMax()
152+
autoScaleMinMaxEnabled = !autoScaleMinMaxEnabled
143153
},
144154
modifier = Modifier.testTag("menuItem_Toggle Auto Scale MinMax")
145155
)
146156
DropdownMenuItem(
147157
text = { Text("Toggle Bar Borders") },
148158
onClick = {
149159
showMenu = false
150-
toggleBarBorders()
160+
barBordersEnabled = !barBordersEnabled
151161
},
152162
modifier = Modifier.testTag("menuItem_Toggle Bar Borders")
153163
)
154164
DropdownMenuItem(
155165
text = { Text("Animate X") },
156166
onClick = {
157167
showMenu = false
158-
animateX()
168+
animationTrigger++
159169
},
160170
modifier = Modifier.testTag("menuItem_Animate X")
161171
)
162172
DropdownMenuItem(
163173
text = { Text("Animate Y") },
164174
onClick = {
165175
showMenu = false
166-
animateY()
176+
animationTrigger++
167177
},
168178
modifier = Modifier.testTag("menuItem_Animate Y")
169179
)
170180
DropdownMenuItem(
171181
text = { Text("Animate XY") },
172182
onClick = {
173183
showMenu = false
174-
animateXY()
184+
animationTrigger++
175185
},
176186
modifier = Modifier.testTag("menuItem_Animate XY")
177187
)
@@ -196,51 +206,74 @@ class HorizontalBarFullComposeActivity : DemoBaseCompose() {
196206
.background(Color.White)
197207
) {
198208
// Chart - Using Compose HorizontalBarChart
199-
val barData = remember(seekBarXValue, seekBarYValue) {
200-
createBarData(seekBarXValue.toInt(), seekBarYValue)
209+
val barData = remember(
210+
seekBarXValue,
211+
seekBarYValue,
212+
showIcons,
213+
barBordersEnabled,
214+
showValues
215+
) {
216+
createBarData(
217+
seekBarXValue.toInt(),
218+
seekBarYValue,
219+
showIcons,
220+
barBordersEnabled,
221+
showValues
222+
)
201223
}
202224

203-
HorizontalBarChart(
204-
data = barData,
205-
modifier = Modifier
206-
.fillMaxWidth()
207-
.weight(1f),
208-
drawValueAboveBar = true,
209-
drawBarShadow = false,
210-
animationDuration = 2500,
211-
onValueSelected = { entry, highlight ->
212-
entry?.let {
213-
Timber.d("Selected: x=${it.x}, y=${it.y}")
225+
key(showIcons) {
226+
HorizontalBarChart(
227+
data = barData,
228+
modifier = Modifier
229+
.fillMaxWidth()
230+
.weight(1f)
231+
.testTag("horizontalBarChart_$showIcons"),
232+
drawValueAboveBar = true,
233+
drawBarShadow = false,
234+
scaleEnabled = pinchZoomEnabled,
235+
touchEnabled = true,
236+
dragEnabled = true,
237+
highlightFullBarEnabled = highlightEnabled,
238+
animationDuration = if (animationTrigger > 0) 2500 else 0,
239+
onValueSelected = { entry, _ ->
240+
entry?.let {
241+
Timber.d("Selected: x=${it.x}, y=${it.y}")
242+
}
243+
},
244+
xAxisConfig = { xAxis ->
245+
xAxis.position = XAxisPosition.BOTTOM
246+
xAxis.typeface = tfLight
247+
xAxis.isDrawAxisLine = true
248+
xAxis.isDrawGridLines = false
249+
xAxis.granularity = 10f
250+
},
251+
leftAxisConfig = { leftAxis ->
252+
leftAxis.typeface = tfLight
253+
leftAxis.isDrawAxisLine = true
254+
leftAxis.isDrawGridLines = true
255+
if (!autoScaleMinMaxEnabled) {
256+
leftAxis.axisMinimum = 0f
257+
}
258+
},
259+
rightAxisConfig = { rightAxis ->
260+
rightAxis.typeface = tfLight
261+
rightAxis.isDrawAxisLine = true
262+
rightAxis.isDrawGridLines = false
263+
if (!autoScaleMinMaxEnabled) {
264+
rightAxis.axisMinimum = 0f
265+
}
266+
},
267+
legend = { legend ->
268+
legend.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM
269+
legend.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT
270+
legend.orientation = Legend.LegendOrientation.HORIZONTAL
271+
legend.setDrawInside(false)
272+
legend.formSize = 8f
273+
legend.xEntrySpace = 4f
214274
}
215-
},
216-
xAxisConfig = { xAxis ->
217-
xAxis.position = XAxisPosition.BOTTOM
218-
xAxis.typeface = tfLight
219-
xAxis.isDrawAxisLine = true
220-
xAxis.isDrawGridLines = false
221-
xAxis.granularity = 10f
222-
},
223-
leftAxisConfig = { leftAxis ->
224-
leftAxis.typeface = tfLight
225-
leftAxis.isDrawAxisLine = true
226-
leftAxis.isDrawGridLines = true
227-
leftAxis.axisMinimum = 0f
228-
},
229-
rightAxisConfig = { rightAxis ->
230-
rightAxis.typeface = tfLight
231-
rightAxis.isDrawAxisLine = true
232-
rightAxis.isDrawGridLines = false
233-
rightAxis.axisMinimum = 0f
234-
},
235-
legend = { legend ->
236-
legend.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM
237-
legend.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT
238-
legend.orientation = Legend.LegendOrientation.HORIZONTAL
239-
legend.setDrawInside(false)
240-
legend.formSize = 8f
241-
legend.xEntrySpace = 4f
242-
}
243-
)
275+
)
276+
}
244277

245278
// SeekBar X with label
246279
Row(
@@ -289,24 +322,33 @@ class HorizontalBarFullComposeActivity : DemoBaseCompose() {
289322
}
290323
}
291324

292-
private fun createBarData(count: Int, range: Float): BarData {
325+
private fun createBarData(count: Int, range: Float, showIcons: Boolean, barBordersEnabled: Boolean, showValues: Boolean): BarData {
293326
val barWidth = 9f
294327
val spaceForBar = 10f
295328
val values = ArrayList<BarEntry>()
296329
val sampleValues = getValues(100)
297330

298331
for (i in 0..<count) {
299332
val value = sampleValues[i]!!.toFloat() * range
300-
val barEntry = BarEntry(
301-
i * spaceForBar, value,
333+
val icon = if (showIcons) {
302334
ResourcesCompat.getDrawable(resources, R.drawable.star, null)
303-
)
335+
} else null
336+
337+
val barEntry = BarEntry(i * spaceForBar, value, icon)
304338
Timber.d("x=${barEntry.x} y=${barEntry.y}")
305339
values.add(barEntry)
306340
}
307341

308342
val set1 = BarDataSet(values, "DataSet 1")
309-
set1.isDrawIcons = false
343+
set1.isDrawIcons = showIcons
344+
set1.isDrawValues = showValues
345+
346+
if (barBordersEnabled) {
347+
set1.barBorderWidth = 1f
348+
set1.barBorderColor = android.graphics.Color.BLACK
349+
} else {
350+
set1.barBorderWidth = 0f
351+
}
310352

311353
val data = BarData(set1)
312354
data.setValueTextSize(10f)
@@ -315,42 +357,5 @@ class HorizontalBarFullComposeActivity : DemoBaseCompose() {
315357
return data
316358
}
317359

318-
// Note: The following methods are not functional with the Compose wrapper
319-
// They would need to be implemented differently using state management
320-
private fun toggleValues() {
321-
Timber.d("toggleValues not yet implemented for Compose wrapper")
322-
}
323-
324-
private fun toggleIcons() {
325-
Timber.d("toggleIcons not yet implemented for Compose wrapper")
326-
}
327-
328-
private fun toggleHighlight() {
329-
Timber.d("toggleHighlight not yet implemented for Compose wrapper")
330-
}
331-
332-
private fun togglePinchZoom() {
333-
Timber.d("togglePinchZoom not yet implemented for Compose wrapper")
334-
}
335-
336-
private fun toggleAutoScaleMinMax() {
337-
Timber.d("toggleAutoScaleMinMax not yet implemented for Compose wrapper")
338-
}
339-
340-
private fun toggleBarBorders() {
341-
Timber.d("toggleBarBorders not yet implemented for Compose wrapper")
342-
}
343-
344-
private fun animateX() {
345-
Timber.d("animateX not yet implemented for Compose wrapper")
346-
}
347-
348-
private fun animateY() {
349-
Timber.d("animateY not yet implemented for Compose wrapper")
350-
}
351-
352-
private fun animateXY() {
353-
Timber.d("animateXY not yet implemented for Compose wrapper")
354-
}
355360

356361
}

0 commit comments

Comments
 (0)