Skip to content

Commit e2c454f

Browse files
committed
fix: missing chart line gradient
1 parent 424cc16 commit e2c454f

2 files changed

Lines changed: 137 additions & 146 deletions

File tree

app/src/androidTest/java/com/tien/piholeconnect/screenshot/ScreenshotContent.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ private fun ScreenshotScaffold(
5555
title = stringResource(screen.labelResourceId),
5656
backButtonEnabled = false,
5757
actions = {
58-
IconButton(onClick = {}) {
59-
Icon(Icons.Default.MoreVert, contentDescription = null)
60-
}
58+
IconButton(onClick = {}) { Icon(Icons.Default.MoreVert, contentDescription = null) }
6159
},
6260
)
6361
},

app/src/main/java/com/tien/piholeconnect/ui/component/Chart.kt

Lines changed: 136 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -48,168 +48,161 @@ fun LineChart(
4848
data: Iterable<LineChartData>,
4949
xAxisFormatter: ((y: Number) -> String)? = null,
5050
) {
51-
ProvideVicoTheme(rememberM3VicoTheme()) {
52-
val modelProducer = remember { CartesianChartModelProducer() }
53-
val dataList = remember(data) { data.toList() }
51+
ProvideVicoTheme(rememberM3VicoTheme()) {
52+
val modelProducer = remember { CartesianChartModelProducer() }
53+
val dataList = remember(data) { data.toList() }
5454

55-
LaunchedEffect(dataList) {
56-
val nonEmpty = dataList.filter { it.data.any() }
57-
if (nonEmpty.isEmpty()) return@LaunchedEffect
55+
LaunchedEffect(dataList) {
56+
val nonEmpty = dataList.filter { it.data.any() }
57+
if (nonEmpty.isEmpty()) return@LaunchedEffect
5858

59-
modelProducer.runTransaction {
60-
extras { extraStore ->
61-
extraStore[BottomAxisSpacingKey] =
62-
maxOf(nonEmpty.maxOf { it.data.count() / 4 }, 1)
59+
modelProducer.runTransaction {
60+
extras { extraStore ->
61+
extraStore[BottomAxisSpacingKey] = maxOf(nonEmpty.maxOf { it.data.count() / 4 }, 1)
6362

64-
if (xAxisFormatter != null) {
65-
extraStore[XAxisLabelKey] =
66-
nonEmpty
67-
.first()
68-
.data
69-
.mapIndexed { index, coordinate ->
70-
index.toDouble() to xAxisFormatter(coordinate.first)
71-
}
72-
.toMap()
63+
if (xAxisFormatter != null) {
64+
extraStore[XAxisLabelKey] =
65+
nonEmpty
66+
.first()
67+
.data
68+
.mapIndexed { index, coordinate ->
69+
index.toDouble() to xAxisFormatter(coordinate.first)
7370
}
74-
}
71+
.toMap()
72+
}
73+
}
7574

76-
lineSeries {
77-
nonEmpty.forEach { lineData ->
78-
if (xAxisFormatter != null) {
79-
series(
80-
x = lineData.data.mapIndexed { index, _ -> index },
81-
y = lineData.data.map { it.second },
82-
)
83-
} else {
84-
series(
85-
x = lineData.data.map { it.first },
86-
y = lineData.data.map { it.second },
87-
)
88-
}
89-
}
90-
}
75+
lineSeries {
76+
nonEmpty.forEach { lineData ->
77+
if (xAxisFormatter != null) {
78+
series(
79+
x = lineData.data.mapIndexed { index, _ -> index },
80+
y = lineData.data.map { it.second },
81+
)
82+
} else {
83+
series(
84+
x = lineData.data.map { it.first },
85+
y = lineData.data.map { it.second },
86+
)
9187
}
88+
}
9289
}
90+
}
91+
}
9392

94-
val defaultColor = MaterialTheme.colorScheme.primary
95-
val lineProvider =
96-
LineCartesianLayer.LineProvider.series(
97-
dataList.map { lineData ->
98-
val color = lineData.color ?: defaultColor
99-
LineCartesianLayer.rememberLine(
100-
fill = LineCartesianLayer.LineFill.single(Fill(color)),
101-
areaFill =
102-
LineCartesianLayer.AreaFill.single(
103-
fill =
104-
Fill(
105-
brush =
106-
Brush.verticalGradient(
107-
colors =
108-
listOf(
109-
color.copy(alpha = 0.3f),
110-
Color.Transparent,
111-
)
112-
)
113-
)
114-
),
115-
pointConnector = LineCartesianLayer.PointConnector.cubic(),
116-
)
117-
}
118-
)
119-
120-
val bottomAxisValueFormatter =
121-
remember(xAxisFormatter) {
122-
if (xAxisFormatter != null) {
123-
CartesianValueFormatter { context, value, _ ->
124-
context.model.extraStore.getOrNull(XAxisLabelKey)?.get(value)
125-
?: value.toInt().toString()
126-
}
127-
} else {
128-
CartesianValueFormatter.decimal()
129-
}
130-
}
93+
val defaultColor = MaterialTheme.colorScheme.primary
94+
val lineProvider =
95+
LineCartesianLayer.LineProvider.series(
96+
dataList.map { lineData ->
97+
val color = lineData.color ?: defaultColor
98+
LineCartesianLayer.rememberLine(
99+
fill = LineCartesianLayer.LineFill.single(Fill(color)),
100+
areaFill =
101+
LineCartesianLayer.AreaFill.single(
102+
fill =
103+
Fill(
104+
brush =
105+
Brush.verticalGradient(
106+
colors =
107+
listOf(
108+
color.copy(alpha = 0.3f),
109+
Color.Transparent,
110+
)))),
111+
pointConnector = LineCartesianLayer.PointConnector.cubic(),
112+
)
113+
})
131114

132-
val endAxisValueFormatter = remember {
133-
CartesianValueFormatter { _, value, _ ->
134-
DecimalFormat("#.##;\u2212#.##").format(value)
115+
val bottomAxisValueFormatter =
116+
remember(xAxisFormatter) {
117+
if (xAxisFormatter != null) {
118+
CartesianValueFormatter { context, value, _ ->
119+
context.model.extraStore.getOrNull(XAxisLabelKey)?.get(value)
120+
?: value.toInt().toString()
135121
}
122+
} else {
123+
CartesianValueFormatter.decimal()
124+
}
136125
}
137126

138-
val bottomAxisItemPlacer = remember {
139-
HorizontalAxis.ItemPlacer.aligned(
140-
spacing = { extraStore -> extraStore.getOrNull(BottomAxisSpacingKey) ?: 1 },
141-
shiftExtremeLines = false,
142-
addExtremeLabelPadding = false,
143-
)
144-
}
127+
val endAxisValueFormatter = remember {
128+
CartesianValueFormatter { _, value, _ -> DecimalFormat("#.##;\u2212#.##").format(value) }
129+
}
145130

146-
val markerValueFormatter = remember {
147-
val defaultFormatter = DefaultCartesianMarker.ValueFormatter.default()
148-
DefaultCartesianMarker.ValueFormatter { context, targets ->
149-
val defaultText = defaultFormatter.format(context, targets)
150-
val x = targets.firstOrNull()?.x ?: return@ValueFormatter defaultText
151-
val timeLabel =
152-
context.model.extraStore.getOrNull(XAxisLabelKey)?.get(x)
153-
?: return@ValueFormatter defaultText
154-
buildAnnotatedString {
155-
append(timeLabel)
156-
append(" (")
157-
append(defaultText)
158-
append(")")
159-
}
160-
}
161-
}
131+
val bottomAxisItemPlacer = remember {
132+
HorizontalAxis.ItemPlacer.aligned(
133+
spacing = { extraStore -> extraStore.getOrNull(BottomAxisSpacingKey) ?: 1 },
134+
shiftExtremeLines = false,
135+
addExtremeLabelPadding = false,
136+
)
137+
}
162138

163-
CartesianChartHost(
164-
chart =
165-
rememberCartesianChart(
166-
rememberLineCartesianLayer(lineProvider = lineProvider),
167-
bottomAxis =
168-
HorizontalAxis.rememberBottom(
169-
line = null,
170-
guideline = null,
171-
itemPlacer = bottomAxisItemPlacer,
172-
valueFormatter = bottomAxisValueFormatter,
173-
),
174-
endAxis =
175-
VerticalAxis.rememberEnd(
176-
line = null,
177-
tick = null,
178-
guideline = null,
179-
valueFormatter = endAxisValueFormatter,
180-
horizontalLabelPosition = VerticalAxis.HorizontalLabelPosition.Inside,
181-
itemPlacer = remember { VerticalAxis.ItemPlacer.count(count = { 3 }) },
182-
),
183-
marker = rememberMarker(valueFormatter = markerValueFormatter),
184-
),
185-
modelProducer = modelProducer,
186-
modifier = modifier,
187-
scrollState = rememberVicoScrollState(scrollEnabled = false),
188-
)
139+
val markerValueFormatter = remember {
140+
val defaultFormatter = DefaultCartesianMarker.ValueFormatter.default()
141+
DefaultCartesianMarker.ValueFormatter { context, targets ->
142+
val defaultText = defaultFormatter.format(context, targets)
143+
val x = targets.firstOrNull()?.x ?: return@ValueFormatter defaultText
144+
val timeLabel =
145+
context.model.extraStore.getOrNull(XAxisLabelKey)?.get(x)
146+
?: return@ValueFormatter defaultText
147+
buildAnnotatedString {
148+
append(timeLabel)
149+
append(" (")
150+
append(defaultText)
151+
append(")")
152+
}
153+
}
189154
}
155+
156+
CartesianChartHost(
157+
chart =
158+
rememberCartesianChart(
159+
rememberLineCartesianLayer(lineProvider = lineProvider),
160+
bottomAxis =
161+
HorizontalAxis.rememberBottom(
162+
line = null,
163+
guideline = null,
164+
itemPlacer = bottomAxisItemPlacer,
165+
valueFormatter = bottomAxisValueFormatter,
166+
),
167+
endAxis =
168+
VerticalAxis.rememberEnd(
169+
line = null,
170+
tick = null,
171+
guideline = null,
172+
valueFormatter = endAxisValueFormatter,
173+
horizontalLabelPosition = VerticalAxis.HorizontalLabelPosition.Inside,
174+
itemPlacer = remember { VerticalAxis.ItemPlacer.count(count = { 3 }) },
175+
),
176+
marker = rememberMarker(valueFormatter = markerValueFormatter),
177+
),
178+
modelProducer = modelProducer,
179+
modifier = modifier,
180+
scrollState = rememberVicoScrollState(scrollEnabled = false),
181+
)
182+
}
190183
}
191184

192185
@Preview(showBackground = true)
193186
@Composable
194187
fun LineChartPreview() {
195-
val formatter = DateFormat.getDateInstance()
196-
PiHoleConnectTheme {
197-
LineChart(
198-
Modifier.fillMaxSize(),
199-
data =
200-
listOf(
201-
LineChartData(
202-
label = "label",
203-
data = listOf(1525546500 to 163, 1525547100 to 154, 1525547700 to 164),
204-
color = MaterialTheme.colorScheme.success,
205-
),
206-
LineChartData(
207-
label = "label",
208-
data = listOf(1525546500 to 30, 1525547100 to 64, 1525547700 to 10),
209-
color = MaterialTheme.colorScheme.error,
210-
),
188+
val formatter = DateFormat.getDateInstance()
189+
PiHoleConnectTheme {
190+
LineChart(
191+
Modifier.fillMaxSize(),
192+
data =
193+
listOf(
194+
LineChartData(
195+
label = "label",
196+
data = listOf(1525546500 to 163, 1525547100 to 154, 1525547700 to 164),
197+
color = MaterialTheme.colorScheme.success,
211198
),
212-
xAxisFormatter = { formatter.format(it) },
213-
)
214-
}
199+
LineChartData(
200+
label = "label",
201+
data = listOf(1525546500 to 30, 1525547100 to 64, 1525547700 to 10),
202+
color = MaterialTheme.colorScheme.error,
203+
),
204+
),
205+
xAxisFormatter = { formatter.format(it) },
206+
)
207+
}
215208
}

0 commit comments

Comments
 (0)