Skip to content

Commit 8a63a31

Browse files
authored
Merge pull request #769 from AppDevNext/TimeIntervalCompose
TimeInterval chart with compose
2 parents 37bf66c + 95629bc commit 8a63a31

12 files changed

+228
-1
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
2828
import info.appdev.chartexample.compose.HorizontalBarComposeActivity
2929
import info.appdev.chartexample.compose.HorizontalBarFullComposeActivity
3030
import info.appdev.chartexample.compose.MultiLineComposeActivity
31+
import info.appdev.chartexample.compose.TimeIntervalComposeActivity
3132
import info.appdev.chartexample.fragments.ViewPagerSimpleChartDemo
3233
import info.appdev.chartexample.notimportant.ContentItem
3334
import info.appdev.chartexample.notimportant.DemoBase
@@ -42,6 +43,7 @@ import org.junit.Test
4243
import org.junit.rules.TestName
4344
import org.junit.runner.RunWith
4445
import timber.log.Timber
46+
import kotlin.jvm.java
4547

4648

4749
@RunWith(AndroidJUnit4::class)
@@ -294,6 +296,7 @@ class StartTest {
294296
contentItem.clazz == LineChartTimeActivity::class.java ||
295297
contentItem.clazz == HorizontalBarComposeActivity::class.java ||
296298
contentItem.clazz == HorizontalBarFullComposeActivity::class.java ||
299+
contentItem.clazz == TimeIntervalComposeActivity::class.java ||
297300
contentItem.clazz == MultiLineComposeActivity::class.java ||
298301
contentItem.clazz == GradientActivity::class.java ||
299302
// contentItem.clazz == TimeIntervalChartActivity::class.java ||

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<activity android:name="info.appdev.chartexample.SpecificPositionsLineChartActivity" />
6262
<activity android:name="info.appdev.chartexample.TimeLineActivity" />
6363
<activity android:name="info.appdev.chartexample.TimeIntervalChartActivity" />
64+
<activity android:name="info.appdev.chartexample.compose.TimeIntervalComposeActivity" />
6465
</application>
6566

6667
</manifest>
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package info.appdev.chartexample.compose
2+
3+
import android.graphics.Color
4+
import android.os.Bundle
5+
import androidx.activity.compose.setContent
6+
import androidx.compose.foundation.background
7+
import androidx.compose.foundation.layout.Box
8+
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.fillMaxSize
11+
import androidx.compose.foundation.layout.fillMaxWidth
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.material.icons.Icons
14+
import androidx.compose.material.icons.filled.MoreVert
15+
import androidx.compose.material3.DropdownMenu
16+
import androidx.compose.material3.DropdownMenuItem
17+
import androidx.compose.material3.ExperimentalMaterial3Api
18+
import androidx.compose.material3.Icon
19+
import androidx.compose.material3.IconButton
20+
import androidx.compose.material3.MaterialTheme
21+
import androidx.compose.material3.Scaffold
22+
import androidx.compose.material3.Slider
23+
import androidx.compose.material3.Text
24+
import androidx.compose.material3.TopAppBar
25+
import androidx.compose.material3.TopAppBarDefaults
26+
import androidx.compose.runtime.Composable
27+
import androidx.compose.runtime.getValue
28+
import androidx.compose.runtime.mutableFloatStateOf
29+
import androidx.compose.runtime.mutableStateOf
30+
import androidx.compose.runtime.remember
31+
import androidx.compose.runtime.setValue
32+
import androidx.compose.ui.Alignment
33+
import androidx.compose.ui.Modifier
34+
import androidx.compose.ui.platform.testTag
35+
import androidx.compose.ui.unit.dp
36+
import info.appdev.chartexample.notimportant.DemoBaseCompose
37+
import info.appdev.charting.compose.GanttChart
38+
import info.appdev.charting.data.GanttChartData
39+
import info.appdev.charting.data.GanttTask
40+
41+
/**
42+
* Demo activity showing Gantt-style timeline visualization using Compose.
43+
*/
44+
class TimeIntervalComposeActivity : DemoBaseCompose() {
45+
46+
// Full list of sample tasks
47+
private val allTasks = listOf(
48+
GanttTask("Design", 0f, 50f, Color.rgb(255, 107, 107)),
49+
GanttTask("Dev", 40f, 100f, Color.rgb(66, 165, 245)),
50+
GanttTask("Testing", 120f, 40f, Color.rgb(76, 175, 80), hatched = true),
51+
GanttTask("Launch", 150f, 20f, Color.rgb(255, 193, 7)),
52+
)
53+
54+
override fun onCreate(savedInstanceState: Bundle?) {
55+
super.onCreate(savedInstanceState)
56+
setContent {
57+
MaterialTheme {
58+
GanttChartScreen(onViewGithub = { viewGithub() })
59+
}
60+
}
61+
}
62+
63+
@OptIn(ExperimentalMaterial3Api::class)
64+
@Composable
65+
fun GanttChartScreen(onViewGithub: () -> Unit) {
66+
var showMenu by remember { mutableStateOf(false) }
67+
// X: controls visible max time (range 50–300)
68+
var seekBarXValue by remember { mutableFloatStateOf(190f) }
69+
// Y: controls how many tasks are shown (1–allTasks.size)
70+
var seekBarYValue by remember { mutableFloatStateOf(allTasks.size.toFloat()) }
71+
72+
Scaffold(
73+
topBar = {
74+
TopAppBar(
75+
title = { Text("TimeIntervalChart") },
76+
colors = TopAppBarDefaults.topAppBarColors(
77+
containerColor = MaterialTheme.colorScheme.primary,
78+
titleContentColor = MaterialTheme.colorScheme.onPrimary
79+
),
80+
actions = {
81+
Box {
82+
IconButton(
83+
onClick = { showMenu = true },
84+
modifier = Modifier.testTag("menuButton")
85+
) {
86+
Icon(
87+
Icons.Default.MoreVert,
88+
contentDescription = "Menu",
89+
tint = MaterialTheme.colorScheme.onPrimary
90+
)
91+
}
92+
DropdownMenu(
93+
expanded = showMenu,
94+
onDismissRequest = { showMenu = false },
95+
modifier = Modifier.testTag("dropdownMenu")
96+
) {
97+
DropdownMenuItem(
98+
text = { Text("View on GitHub") },
99+
onClick = { showMenu = false; onViewGithub() },
100+
modifier = Modifier.testTag("menuItem_View on GitHub")
101+
)
102+
}
103+
}
104+
}
105+
)
106+
}
107+
) { paddingValues ->
108+
Column(
109+
modifier = Modifier
110+
.fillMaxSize()
111+
.padding(paddingValues)
112+
.background(androidx.compose.ui.graphics.Color.White)
113+
) {
114+
val ganttData = remember(seekBarXValue, seekBarYValue) {
115+
val maxTime = seekBarXValue
116+
val taskCount = seekBarYValue.toInt().coerceAtLeast(1)
117+
GanttChartData().apply {
118+
allTasks.take(taskCount).forEach { addTask(it) }
119+
minTime = 0f
120+
this.maxTime = maxTime
121+
}
122+
}
123+
124+
GanttChart(
125+
data = ganttData,
126+
modifier = Modifier
127+
.fillMaxWidth()
128+
.weight(1f)
129+
)
130+
131+
// SeekBar X – controls visible time range
132+
Row(
133+
modifier = Modifier
134+
.fillMaxWidth()
135+
.padding(horizontal = 16.dp, vertical = 8.dp),
136+
verticalAlignment = Alignment.CenterVertically
137+
) {
138+
Text(
139+
text = "X:",
140+
modifier = Modifier.padding(end = 8.dp),
141+
style = MaterialTheme.typography.bodyMedium
142+
)
143+
Slider(
144+
value = seekBarXValue,
145+
onValueChange = { seekBarXValue = it },
146+
valueRange = 1f..200f,
147+
modifier = Modifier.weight(1f)
148+
)
149+
Text(
150+
text = seekBarXValue.toInt().toString(),
151+
modifier = Modifier.padding(start = 8.dp),
152+
style = MaterialTheme.typography.bodyMedium
153+
)
154+
}
155+
156+
// SeekBar Y – controls number of tasks shown
157+
Row(
158+
modifier = Modifier
159+
.fillMaxWidth()
160+
.padding(horizontal = 16.dp, vertical = 8.dp),
161+
verticalAlignment = Alignment.CenterVertically
162+
) {
163+
Text(
164+
text = "Y:",
165+
modifier = Modifier.padding(end = 8.dp),
166+
style = MaterialTheme.typography.bodyMedium
167+
)
168+
Slider(
169+
value = seekBarYValue,
170+
onValueChange = { seekBarYValue = it },
171+
valueRange = 1f..allTasks.size.toFloat(),
172+
steps = allTasks.size - 2,
173+
modifier = Modifier.weight(1f)
174+
)
175+
Text(
176+
text = seekBarYValue.toInt().toString(),
177+
modifier = Modifier.padding(start = 8.dp),
178+
style = MaterialTheme.typography.bodyMedium
179+
)
180+
}
181+
}
182+
}
183+
}
184+
}

app/src/main/kotlin/info/appdev/chartexample/notimportant/MainActivity.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import info.appdev.chartexample.TimeLineActivity
8080
import info.appdev.chartexample.compose.HorizontalBarComposeActivity
8181
import info.appdev.chartexample.compose.HorizontalBarFullComposeActivity
8282
import info.appdev.chartexample.compose.MultiLineComposeActivity
83+
import info.appdev.chartexample.compose.TimeIntervalComposeActivity
8384
import info.appdev.chartexample.fragments.ViewPagerSimpleChartDemo
8485
import info.appdev.charting.utils.Utils
8586
import info.appdev.charting.utils.initUtils
@@ -217,10 +218,13 @@ class MainActivity : ComponentActivity() {
217218
add(ComposeItem("HorizontalFullCompose", "Render bar chart horizontally full compose.", HorizontalBarFullComposeActivity::class.java).toDemoBase())
218219
add(ComposeItem("MultiLineCompose", "Show multiple data sets in compose.", MultiLineComposeActivity::class.java).toDemoBase())
219220

221+
add(ContentItem("Timeinterval"))
222+
add(ContentItem("Timeinterval", "Grantt chart", TimeIntervalChartActivity::class.java))
223+
add(ComposeItem("Timeinterval compose", "Grantt chart compose", TimeIntervalComposeActivity::class.java).toDemoBase())
224+
220225
add(ContentItem("Demonstrate and fix issues"))
221226
add(ContentItem("Gradient", "Show a gradient edge case", GradientActivity::class.java))
222227
add(ContentItem("Timeline", "Show a time line with Unix timestamp", TimeLineActivity::class.java))
223-
add(ContentItem("Timeinterval", "Grantt chart", TimeIntervalChartActivity::class.java))
224228
}
225229
}
226230
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package info.appdev.charting.compose
2+
3+
import androidx.compose.foundation.layout.fillMaxSize
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.remember
6+
import androidx.compose.ui.Modifier
7+
import androidx.compose.ui.platform.LocalContext
8+
import androidx.compose.ui.viewinterop.AndroidView
9+
import info.appdev.charting.charts.GanttChart
10+
import info.appdev.charting.data.GanttChartData
11+
12+
/**
13+
* A Composable wrapper for [GanttChart].
14+
*
15+
* @param data The Gantt chart data to display
16+
* @param modifier The modifier to be applied to the chart
17+
*/
18+
@Composable
19+
fun GanttChart(
20+
data: GanttChartData?,
21+
modifier: Modifier = Modifier,
22+
) {
23+
val context = LocalContext.current
24+
25+
val chart = remember { GanttChart(context) }
26+
27+
AndroidView(
28+
factory = { chart },
29+
modifier = modifier.fillMaxSize(),
30+
update = { ganttChart ->
31+
ganttChart.setData(data)
32+
}
33+
)
34+
}
35+

screenshotsToCompare9/StartTest_smokeTestStart-46-TimeIntervalChartActivity-Timeinterval-1SampleClick.png renamed to screenshotsToCompare9/StartTest_smokeTestStart-44-TimeIntervalChartActivity-Timeinterval-1SampleClick.png

File renamed without changes.

screenshotsToCompare9/StartTest_smokeTestStart-46-TimeIntervalChartActivity-Timeinterval-click.png renamed to screenshotsToCompare9/StartTest_smokeTestStart-44-TimeIntervalChartActivity-Timeinterval-click.png

File renamed without changes.

screenshotsToCompare9/StartTest_smokeTestStart-46-TimeIntervalChartActivity-Timeinterval-click2020.png renamed to screenshotsToCompare9/StartTest_smokeTestStart-44-TimeIntervalChartActivity-Timeinterval-click2020.png

File renamed without changes.

screenshotsToCompare9/StartTest_smokeTestStart-46-TimeIntervalChartActivity-Timeinterval-click7070.png renamed to screenshotsToCompare9/StartTest_smokeTestStart-44-TimeIntervalChartActivity-Timeinterval-click7070.png

File renamed without changes.
17.2 KB
Loading

0 commit comments

Comments
 (0)