diff --git a/Reef/src/main/java/dev/pranav/reef/util/TimeColumnChart.kt b/Reef/src/main/java/dev/pranav/reef/util/TimeColumnChart.kt index c312e5c..45c4b2b 100644 --- a/Reef/src/main/java/dev/pranav/reef/util/TimeColumnChart.kt +++ b/Reef/src/main/java/dev/pranav/reef/util/TimeColumnChart.kt @@ -2,7 +2,8 @@ * Copyright (c) 2025 Nishant Mishra * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. + * If not, see . */ package org.nsh07.pomodoro.ui.statsScreen @@ -34,6 +35,7 @@ import com.patrykandpatrick.vico.compose.common.MarkerCornerBasedShape import com.patrykandpatrick.vico.compose.common.ProvideVicoTheme import com.patrykandpatrick.vico.compose.common.component.rememberLineComponent import com.patrykandpatrick.vico.compose.m3.common.rememberM3VicoTheme +import kotlin.math.roundToInt @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable @@ -51,46 +53,43 @@ internal fun TimeColumnChart( ) { if (dataValues.isEmpty()) return - val radius = with(LocalDensity.current) { - (thickness / 2).toPx() - } - var chartSize by remember { mutableStateOf(IntSize.Zero) } val density = LocalDensity.current - val primaryColor = MaterialTheme.colorScheme.primary + // Use a dedicated scrollState variable to track horizontal movement + val vicoScrollState = rememberVicoScrollState(initialScroll = Scroll.Absolute.End) + ProvideVicoTheme(rememberM3VicoTheme()) { CartesianChartHost( - chart = - rememberCartesianChart( - rememberColumnCartesianLayer( - ColumnCartesianLayer.ColumnProvider.series( - dataValues.indices.map { _ -> - rememberLineComponent( - fill = Fill(primaryColor), - thickness = thickness, - shape = MarkerCornerBasedShape(RoundedCornerShape(16.dp)) - ) - } - ), - columnCollectionSpacing = columnCollectionSpacing - ), - startAxis = VerticalAxis.rememberStart( - valueFormatter = yValueFormatter + chart = rememberCartesianChart( + rememberColumnCartesianLayer( + ColumnCartesianLayer.ColumnProvider.series( + dataValues.indices.map { _ -> + rememberLineComponent( + fill = Fill(primaryColor), + thickness = thickness, + shape = MarkerCornerBasedShape(RoundedCornerShape(16.dp)) + ) + } ), - bottomAxis = HorizontalAxis.rememberBottom( - guideline = rememberLineComponent(Fill.Transparent), - valueFormatter = xValueFormatter - ) + columnCollectionSpacing = columnCollectionSpacing ), + startAxis = VerticalAxis.rememberStart( + valueFormatter = yValueFormatter + ), + bottomAxis = HorizontalAxis.rememberBottom( + guideline = rememberLineComponent(Fill.Transparent), + valueFormatter = xValueFormatter + ) + ), modelProducer = modelProducer, zoomState = rememberVicoZoomState( zoomEnabled = false, initialZoom = Zoom.fixed(), minZoom = Zoom.min(Zoom.Content, Zoom.fixed()) ), - scrollState = rememberVicoScrollState(initialScroll = Scroll.Absolute.End), + scrollState = vicoScrollState, animationSpec = animationSpec, modifier = modifier .onSizeChanged { chartSize = it } @@ -104,28 +103,35 @@ internal fun TimeColumnChart( val endPadding = with(density) { 16.dp.toPx() } val bottomAxisHeight = with(density) { 32.dp.toPx() } val topPadding = with(density) { 8.dp.toPx() } - val availableWidth = chartWidth - startAxisWidth - endPadding + val availableHeight = chartHeight - bottomAxisHeight - topPadding val columnWidth = with(density) { thickness.toPx() } val spacing = with(density) { columnCollectionSpacing.toPx() } val totalColumnWidth = columnWidth + spacing - val clickX = offset.x - startAxisWidth + // Correcting coordinate: Add current scroll offset to the tap position relative to the chart start + val scrollOffset = vicoScrollState.value + val relativeTapX = offset.x - startAxisWidth + val absoluteX = relativeTapX + scrollOffset val clickY = offset.y - topPadding - if (clickX in 0.0f..availableWidth && clickY >= 0 && clickY <= availableHeight) { - val columnIndex = (clickX / totalColumnWidth).toInt() - if (columnIndex >= 0 && columnIndex < dataValues.size) { - val maxValue = dataValues.maxOrNull() ?: 1f - val barHeightRatio = - if (maxValue > 0) dataValues[columnIndex] / maxValue else 0f - val barHeight = availableHeight * barHeightRatio - val barTop = availableHeight - barHeight + // Ensure tap is within the horizontal bounds of the chart content + if (offset.x in startAxisWidth..(chartWidth - endPadding) && + clickY in 0f..availableHeight) { + + // Using integer division for more predictable column mapping + val columnIndex = (absoluteX / totalColumnWidth).toInt() + .coerceIn(0, dataValues.size - 1) - if (clickY in barTop..availableHeight) { - onColumnClick(columnIndex) - } + val maxValue = dataValues.maxOrNull() ?: 1f + val barHeightRatio = if (maxValue > 0) dataValues[columnIndex] / maxValue else 0f + val barHeight = availableHeight * barHeightRatio + val barTop = availableHeight - barHeight + + // Trigger callback if the tap falls within the column's vertical area + if (clickY in barTop..availableHeight) { + onColumnClick(columnIndex) } } } @@ -186,4 +192,4 @@ internal fun TimeLineChart( modifier = modifier ) } -} +} \ No newline at end of file