From 8ab06d8d7eb31b1535db7426de8c04b3265345c0 Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Sat, 13 Dec 2025 10:39:35 +0530 Subject: [PATCH] feat(stats): re-add focus breakdown chart --- .../components/FocusBreakdownChart.kt | 58 +++++++++++++++++++ .../ui/statsScreen/screens/LastWeekScreen.kt | 49 +++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/FocusBreakdownChart.kt diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/FocusBreakdownChart.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/FocusBreakdownChart.kt new file mode 100644 index 0000000..6ec3b60 --- /dev/null +++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/FocusBreakdownChart.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Nishant Mishra + * + * This file is part of Tomato - a minimalist pomodoro timer for Android. + * + * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tomato. + * If not, see . + */ + +package org.nsh07.pomodoro.ui.statsScreen.components + +import android.graphics.Typeface +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer +import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter +import org.nsh07.pomodoro.R + +@Composable +fun ColumnScope.FocusBreakdownChart( + expanded: Boolean, + modelProducer: CartesianChartModelProducer, + modifier: Modifier = Modifier, + axisTypeface: Typeface = Typeface.DEFAULT, + markerTypeface: Typeface = Typeface.DEFAULT +) { + AnimatedVisibility(expanded) { + TimeColumnChart( + modelProducer, + hoursFormat = stringResource(R.string.hours_format), + hoursMinutesFormat = stringResource(R.string.hours_and_minutes_format), + minutesFormat = stringResource(R.string.minutes_format), + axisTypeface = axisTypeface, + markerTypeface = markerTypeface, + xValueFormatter = CartesianValueFormatter { _, value, _ -> + when (value) { + 0.0 -> "0 - 6" + 1.0 -> "6 - 12" + 2.0 -> "12 - 18" + 3.0 -> "18 - 24" + else -> "" + } + }, + modifier = modifier + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/LastWeekScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/LastWeekScreen.kt index e916ec7..890063b 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/LastWeekScreen.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/LastWeekScreen.kt @@ -19,17 +19,20 @@ package org.nsh07.pomodoro.ui.statsScreen.screens import android.graphics.Typeface import androidx.compose.animation.SharedTransitionScope +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FilledTonalIconButton @@ -39,12 +42,18 @@ import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TonalToggleButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -54,10 +63,12 @@ import androidx.compose.ui.util.fastForEach import androidx.navigation3.ui.LocalNavAnimatedContentScope import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter +import com.patrykandpatrick.vico.core.cartesian.data.columnSeries import com.patrykandpatrick.vico.core.common.data.ExtraStore import org.nsh07.pomodoro.R import org.nsh07.pomodoro.ui.mergePaddingValues import org.nsh07.pomodoro.ui.statsScreen.components.FocusBreakRatioVisualization +import org.nsh07.pomodoro.ui.statsScreen.components.FocusBreakdownChart import org.nsh07.pomodoro.ui.statsScreen.components.HorizontalStackedBar import org.nsh07.pomodoro.ui.statsScreen.components.TimeColumnChart import org.nsh07.pomodoro.ui.statsScreen.components.sharedBoundsReveal @@ -83,6 +94,17 @@ fun SharedTransitionScope.LastWeekScreen( ) { val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + val lastWeekSummaryAnalysisModelProducer = remember { CartesianChartModelProducer() } + var breakdownChartExpanded by remember { mutableStateOf(false) } + + LaunchedEffect(lastWeekAnalysisValues.first) { + lastWeekSummaryAnalysisModelProducer.runTransaction { + columnSeries { + series(lastWeekAnalysisValues.first) + } + } + } + val rankList = remember(lastWeekAnalysisValues) { val sortedIndices = lastWeekAnalysisValues.first.indices.sortedByDescending { lastWeekAnalysisValues.first[it] } @@ -232,7 +254,32 @@ fun SharedTransitionScope.LastWeekScreen( } } - item { Spacer(Modifier.height(8.dp)) } + item { + val iconRotation by animateFloatAsState( + if (breakdownChartExpanded) 180f else 0f + ) + Column(modifier = Modifier.fillMaxWidth()) { + TonalToggleButton( + checked = breakdownChartExpanded, + onCheckedChange = { breakdownChartExpanded = it }, + modifier = Modifier.align(Alignment.End) + ) { + Icon( + painterResource(R.drawable.arrow_down), + stringResource(R.string.more_info), + modifier = Modifier.rotate(iconRotation) + ) + Spacer(Modifier.width(ButtonDefaults.IconSpacing)) + Text("Show chart") + } + + FocusBreakdownChart( + expanded = breakdownChartExpanded, + modelProducer = lastWeekSummaryAnalysisModelProducer, + modifier = Modifier.padding(top = 16.dp, bottom = 24.dp) + ) + } + } item { Text(