diff --git a/app/src/main/java/org/nsh07/pomodoro/data/Stat.kt b/app/src/main/java/org/nsh07/pomodoro/data/Stat.kt
index 2110244..b97a564 100644
--- a/app/src/main/java/org/nsh07/pomodoro/data/Stat.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/data/Stat.kt
@@ -1,8 +1,18 @@
/*
* Copyright (c) 2025 Nishant Mishra
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * 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.data
@@ -29,17 +39,10 @@ data class Stat(
fun totalFocusTime() = focusTimeQ1 + focusTimeQ2 + focusTimeQ3 + focusTimeQ4
}
-data class StatSummary(
- val date: LocalDate,
- val focusTime: Long,
- val breakTime: Long
-)
-
-data class StatFocusTime(
+data class StatTime(
val focusTimeQ1: Long,
val focusTimeQ2: Long,
val focusTimeQ3: Long,
- val focusTimeQ4: Long
-) {
- fun total() = focusTimeQ1 + focusTimeQ2 + focusTimeQ3 + focusTimeQ4
-}
\ No newline at end of file
+ val focusTimeQ4: Long,
+ val breakTime: Long,
+)
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt b/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt
index a58aff0..87877ea 100644
--- a/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt
@@ -1,8 +1,18 @@
/*
* Copyright (c) 2025 Nishant Mishra
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * 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.data
@@ -37,23 +47,24 @@ interface StatDao {
@Query("SELECT * FROM stat WHERE date = :date")
fun getStat(date: LocalDate): Flow
- @Query("SELECT date, focusTimeQ1 + focusTimeQ2 + focusTimeQ3 + focusTimeQ4 as focusTime, breakTime FROM stat ORDER BY date DESC LIMIT :n")
- fun getLastNDaysStatsSummary(n: Int): Flow>
+ @Query("SELECT date, focusTimeQ1, focusTimeQ2, focusTimeQ3, focusTimeQ4, breakTime FROM stat ORDER BY date DESC LIMIT :n")
+ fun getLastNDaysStats(n: Int): Flow>
@Query(
"SELECT " +
"AVG(focusTimeQ1) AS focusTimeQ1, " +
"AVG(focusTimeQ2) AS focusTimeQ2, " +
"AVG(focusTimeQ3) AS focusTimeQ3, " +
- "AVG(focusTimeQ4) AS focusTimeQ4 " +
+ "AVG(focusTimeQ4) AS focusTimeQ4, " +
+ "AVG(breakTime) AS breakTime " +
"FROM (" +
"SELECT * FROM (" +
- "SELECT focusTimeQ1, focusTimeQ2, focusTimeQ3, focusTimeQ4 FROM stat ORDER BY date DESC LIMIT :n" +
+ "SELECT focusTimeQ1, focusTimeQ2, focusTimeQ3, focusTimeQ4, breakTime FROM stat ORDER BY date DESC LIMIT :n" +
") " +
"WHERE focusTimeQ1 != 0 OR focusTimeQ2 != 0 OR focusTimeQ3 != 0 OR focusTimeQ4 != 0 " +
")"
)
- fun getLastNDaysAvgFocusTimes(n: Int): Flow
+ fun getLastNDaysAvgStats(n: Int): Flow
@Query("SELECT EXISTS (SELECT * FROM stat WHERE date = :date)")
suspend fun statExists(date: LocalDate): Boolean
diff --git a/app/src/main/java/org/nsh07/pomodoro/data/StatRepository.kt b/app/src/main/java/org/nsh07/pomodoro/data/StatRepository.kt
index 7d2efbd..438fb48 100644
--- a/app/src/main/java/org/nsh07/pomodoro/data/StatRepository.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/data/StatRepository.kt
@@ -1,8 +1,18 @@
/*
* Copyright (c) 2025 Nishant Mishra
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * 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.data
@@ -28,9 +38,9 @@ interface StatRepository {
fun getTodayStat(): Flow
- fun getLastNDaysStatsSummary(n: Int): Flow>
+ fun getLastNDaysStats(n: Int): Flow>
- fun getLastNDaysAverageFocusTimes(n: Int): Flow
+ fun getLastNDaysAverageFocusTimes(n: Int): Flow
suspend fun getLastDate(): LocalDate?
}
@@ -101,11 +111,11 @@ class AppStatRepository(
return statDao.getStat(currentDate)
}
- override fun getLastNDaysStatsSummary(n: Int): Flow> =
- statDao.getLastNDaysStatsSummary(n)
+ override fun getLastNDaysStats(n: Int): Flow> =
+ statDao.getLastNDaysStats(n)
- override fun getLastNDaysAverageFocusTimes(n: Int): Flow =
- statDao.getLastNDaysAvgFocusTimes(n)
+ override fun getLastNDaysAverageFocusTimes(n: Int): Flow =
+ statDao.getLastNDaysAvgStats(n)
override suspend fun getLastDate(): LocalDate? = statDao.getLastDate()
}
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/StatsScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/StatsScreen.kt
index ea3f277..7b7319f 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/StatsScreen.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/StatsScreen.kt
@@ -62,6 +62,7 @@ fun StatsScreenRoot(
val todayStat by viewModel.todayStat.collectAsStateWithLifecycle(null)
val lastWeekSummaryChartData by viewModel.lastWeekSummaryChartData.collectAsStateWithLifecycle()
+ val lastWeekSummaryValues by viewModel.lastWeekStats.collectAsStateWithLifecycle()
val lastWeekAnalysisValues by viewModel.lastWeekAverageFocusTimes.collectAsStateWithLifecycle()
val lastMonthSummaryChartData by viewModel.lastMonthSummaryChartData.collectAsStateWithLifecycle()
@@ -74,10 +75,11 @@ fun StatsScreenRoot(
contentPadding = contentPadding,
backStack = backStack,
lastWeekSummaryChartData = lastWeekSummaryChartData,
+ lastWeekSummaryValues = lastWeekSummaryValues,
lastMonthSummaryChartData = lastMonthSummaryChartData,
lastYearSummaryChartData = lastYearSummaryChartData,
todayStat = todayStat,
- lastWeekAverageFocusTimes = lastWeekAnalysisValues,
+ lastWeekAnalysisValues = lastWeekAnalysisValues,
lastMonthAverageFocusTimes = lastMonthAnalysisValues,
lastYearAverageFocusTimes = lastYearAnalysisValues,
generateSampleData = viewModel::generateSampleData,
@@ -94,10 +96,11 @@ fun StatsScreen(
contentPadding: PaddingValues,
backStack: SnapshotStateList,
lastWeekSummaryChartData: Pair>>,
+ lastWeekSummaryValues: List>>,
lastMonthSummaryChartData: Pair>>,
lastYearSummaryChartData: Pair>>,
todayStat: Stat?,
- lastWeekAverageFocusTimes: List,
+ lastWeekAnalysisValues: Pair, Long>,
lastMonthAverageFocusTimes: List,
lastYearAverageFocusTimes: List,
generateSampleData: () -> Unit,
@@ -134,7 +137,7 @@ fun StatsScreen(
lastMonthSummaryChartData = lastMonthSummaryChartData,
lastYearSummaryChartData = lastYearSummaryChartData,
todayStat = todayStat,
- lastWeekAverageFocusTimes = lastWeekAverageFocusTimes,
+ lastWeekAverageFocusTimes = lastWeekAnalysisValues.first,
lastMonthAverageFocusTimes = lastMonthAverageFocusTimes,
lastYearAverageFocusTimes = lastYearAverageFocusTimes,
generateSampleData = generateSampleData,
@@ -154,10 +157,11 @@ fun StatsScreen(
entry {
LastWeekScreen(
contentPadding = contentPadding,
- lastWeekAverageFocusTimes = lastWeekAverageFocusTimes,
+ lastWeekAnalysisValues = lastWeekAnalysisValues,
+ lastWeekSummaryValues = lastWeekSummaryValues,
+ lastWeekSummaryChartData = lastWeekSummaryChartData,
onBack = backStack::removeLastOrNull,
hoursMinutesFormat = hoursMinutesFormat,
- lastWeekSummaryChartData = lastWeekSummaryChartData,
hoursFormat = hoursFormat,
minutesFormat = minutesFormat,
axisTypeface = axisTypeface,
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/sharedBoundsReveal.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/sharedBoundsReveal.kt
index d89847f..30ed8c1 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/sharedBoundsReveal.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/sharedBoundsReveal.kt
@@ -23,6 +23,8 @@ import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.SharedTransitionDefaults
import androidx.compose.animation.SharedTransitionScope
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
@@ -37,8 +39,8 @@ fun Modifier.sharedBoundsReveal(
sharedTransitionScope: SharedTransitionScope,
animatedVisibilityScope: AnimatedVisibilityScope = LocalNavAnimatedContentScope.current,
boundsTransform: BoundsTransform = SharedTransitionDefaults.BoundsTransform,
- enter: EnterTransition = EnterTransition.None,
- exit: ExitTransition = ExitTransition.None,
+ enter: EnterTransition = fadeIn(),
+ exit: ExitTransition = fadeOut(),
resizeMode: SharedTransitionScope.ResizeMode = SharedTransitionScope.ResizeMode.RemeasureToBounds,
clipShape: Shape = MaterialTheme.shapes.largeIncreased,
renderInOverlayDuringTransition: Boolean = true,
@@ -55,7 +57,7 @@ fun Modifier.sharedBoundsReveal(
clipInOverlayDuringTransition = OverlayClip(clipShape),
renderInOverlayDuringTransition = renderInOverlayDuringTransition,
)
- .skipToLookaheadSize()
- .skipToLookaheadPosition()
+// .skipToLookaheadSize()
+// .skipToLookaheadPosition()
}
}
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/VariableWidth1DHeatmap.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/visualizations.kt
similarity index 68%
rename from app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/VariableWidth1DHeatmap.kt
rename to app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/visualizations.kt
index 573b22e..a27ded3 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/VariableWidth1DHeatmap.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/components/visualizations.kt
@@ -25,9 +25,12 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.shapes
+import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.tooling.preview.Preview
@@ -35,6 +38,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import org.nsh07.pomodoro.ui.theme.TomatoTheme
+import kotlin.math.roundToInt
/**
* A custom implementation of the 1-Dimensional heatmap plot that varies the width of the cells
@@ -98,6 +102,60 @@ fun VariableWidth1DHeatmap(
}
}
+@Composable
+fun FocusBreakRatioVisualization(
+ focusDuration: Long,
+ breakDuration: Long,
+ modifier: Modifier = Modifier,
+ height: Dp = 40.dp,
+ gap: Dp = 2.dp
+) {
+ val focusPercentage = ((focusDuration / (focusDuration.toFloat() + breakDuration)) * 100)
+ val breakPercentage = ((breakDuration / (focusDuration.toFloat() + breakDuration)) * 100)
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(gap),
+ modifier = modifier
+ ) {
+ Text(
+ text = focusPercentage.roundToInt().toString() + '%',
+ style = typography.bodyLarge,
+ color = colorScheme.primary,
+ modifier = Modifier.padding(end = 6.dp)
+ )
+ Spacer(
+ Modifier
+ .weight(focusPercentage)
+ .height(height)
+ .background(
+ colorScheme.primary,
+ shapes.large.copy(
+ topEnd = shapes.extraSmall.topEnd,
+ bottomEnd = shapes.extraSmall.bottomEnd
+ )
+ )
+ )
+ Spacer(
+ Modifier
+ .weight(breakPercentage)
+ .height(height)
+ .background(
+ colorScheme.tertiary,
+ shapes.large.copy(
+ topStart = shapes.extraSmall.topStart,
+ bottomStart = shapes.extraSmall.bottomStart
+ )
+ )
+ )
+ Text(
+ text = breakPercentage.roundToInt().toString() + '%',
+ style = typography.bodyLarge,
+ color = colorScheme.tertiary,
+ modifier = Modifier.padding(start = 6.dp)
+ )
+ }
+}
+
@Preview
@Composable
fun VariableWidth1DHeatmapPreview() {
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 8921cfe..adb64a6 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,14 +19,15 @@ package org.nsh07.pomodoro.ui.statsScreen.screens
import android.graphics.Typeface
import androidx.compose.animation.SharedTransitionScope
-import androidx.compose.foundation.background
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.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
@@ -46,28 +47,34 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
+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.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.TimeColumnChart
+import org.nsh07.pomodoro.ui.statsScreen.components.VariableWidth1DHeatmap
import org.nsh07.pomodoro.ui.statsScreen.components.sharedBoundsReveal
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape
import org.nsh07.pomodoro.utils.millisecondsToHoursMinutes
+import org.nsh07.pomodoro.utils.millisecondsToMinutes
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun SharedTransitionScope.LastWeekScreen(
contentPadding: PaddingValues,
- lastWeekAverageFocusTimes: List,
+ lastWeekAnalysisValues: Pair, Long>,
+ lastWeekSummaryValues: List>>,
+ lastWeekSummaryChartData: Pair>>,
onBack: () -> Unit,
modifier: Modifier = Modifier,
hoursMinutesFormat: String,
- lastWeekSummaryChartData: Pair>>,
hoursFormat: String,
minutesFormat: String,
axisTypeface: Typeface,
@@ -75,10 +82,10 @@ fun SharedTransitionScope.LastWeekScreen(
) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
- val rankList = remember(lastWeekAverageFocusTimes) {
+ val rankList = remember(lastWeekAnalysisValues) {
val sortedIndices =
- lastWeekAverageFocusTimes.indices.sortedByDescending { lastWeekAverageFocusTimes[it] }
- val ranks = MutableList(lastWeekAverageFocusTimes.size) { 0 }
+ lastWeekAnalysisValues.first.indices.sortedByDescending { lastWeekAnalysisValues.first[it] }
+ val ranks = MutableList(lastWeekAnalysisValues.first.size) { 0 }
sortedIndices.forEachIndexed { rank, originalIndex ->
ranks[originalIndex] = rank
@@ -87,6 +94,10 @@ fun SharedTransitionScope.LastWeekScreen(
ranks
}
+ val focusDuration = remember(lastWeekAnalysisValues) {
+ lastWeekAnalysisValues.first.sum()
+ }
+
Scaffold(
topBar = {
TopAppBar(
@@ -115,11 +126,7 @@ fun SharedTransitionScope.LastWeekScreen(
)
}
},
- scrollBehavior = scrollBehavior,
- colors = TopAppBarDefaults.topAppBarColors(
- containerColor = colorScheme.surfaceBright,
- scrolledContainerColor = colorScheme.surfaceBright
- )
+ scrollBehavior = scrollBehavior
)
},
modifier = modifier
@@ -135,11 +142,10 @@ fun SharedTransitionScope.LastWeekScreen(
) { innerPadding ->
val insets = mergePaddingValues(innerPadding, contentPadding)
LazyColumn(
- verticalArrangement = Arrangement.spacedBy(8.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = insets,
modifier = Modifier
.fillMaxSize()
- .background(colorScheme.surfaceBright)
.padding(horizontal = 16.dp)
) {
item {
@@ -150,9 +156,7 @@ fun SharedTransitionScope.LastWeekScreen(
) {
Text(
millisecondsToHoursMinutes(
- remember(lastWeekAverageFocusTimes) {
- lastWeekAverageFocusTimes.sum().toLong()
- },
+ focusDuration,
hoursMinutesFormat
),
style = typography.displaySmall,
@@ -175,7 +179,8 @@ fun SharedTransitionScope.LastWeekScreen(
)
)
}
- Spacer(Modifier.height(16.dp))
+ }
+ item {
TimeColumnChart(
modelProducer = lastWeekSummaryChartData.first,
hoursFormat = hoursFormat,
@@ -194,6 +199,79 @@ fun SharedTransitionScope.LastWeekScreen(
)
)
}
+
+ item { Spacer(Modifier.height(8.dp)) }
+
+ item {
+ Text(
+ "Focus overview",
+ style = typography.headlineSmall
+ )
+ Text(
+ "Average focus durations at different times of the day",
+ style = typography.bodySmall,
+ color = colorScheme.onSurfaceVariant
+ )
+ }
+ item { VariableWidth1DHeatmap(lastWeekAnalysisValues.first, rankList = rankList) }
+ item {
+ Row {
+ lastWeekAnalysisValues.first.fastForEach {
+ Text(
+ if (it <= 60 * 60 * 1000)
+ millisecondsToMinutes(it, minutesFormat)
+ else millisecondsToHoursMinutes(it, hoursMinutesFormat),
+ style = typography.bodyLarge,
+ textAlign = TextAlign.Center,
+ color = colorScheme.onSurfaceVariant,
+ modifier = Modifier.weight(1f)
+ )
+ }
+ }
+ }
+
+ item { Spacer(Modifier.height(8.dp)) }
+
+ item {
+ Text(
+ stringResource(R.string.focus_break_ratio),
+ style = typography.headlineSmall
+ )
+ }
+ item {
+ FocusBreakRatioVisualization(
+ focusDuration = focusDuration,
+ breakDuration = lastWeekAnalysisValues.second
+ )
+ }
+
+ item { Spacer(Modifier.height(8.dp)) }
+
+ item {
+ Text(
+ "Focus insights",
+ style = typography.headlineSmall
+ )
+ Text(
+ "Focus overview of each day of the past week",
+ style = typography.bodySmall,
+ color = colorScheme.onSurfaceVariant
+ )
+ }
+ item {
+ Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
+ lastWeekSummaryValues.fastForEach {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Text(
+ it.first,
+ style = typography.labelSmall,
+ modifier = Modifier.size(18.dp)
+ )
+ VariableWidth1DHeatmap(it.second, rankList = rankList)
+ }
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/StatsMainScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/StatsMainScreen.kt
index c428a67..b51d2d5 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/StatsMainScreen.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/screens/StatsMainScreen.kt
@@ -82,7 +82,7 @@ fun SharedTransitionScope.StatsMainScreen(
lastMonthSummaryChartData: Pair>>,
lastYearSummaryChartData: Pair>>,
todayStat: Stat?,
- lastWeekAverageFocusTimes: List,
+ lastWeekAverageFocusTimes: List,
lastMonthAverageFocusTimes: List,
lastYearAverageFocusTimes: List,
generateSampleData: () -> Unit,
@@ -254,7 +254,7 @@ fun SharedTransitionScope.StatsMainScreen(
Text(
millisecondsToHoursMinutes(
remember(lastWeekAverageFocusTimes) {
- lastWeekAverageFocusTimes.sum().toLong()
+ lastWeekAverageFocusTimes.sum()
},
hoursMinutesFormat
),
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/viewModel/StatsViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/viewModel/StatsViewModel.kt
index f2b7362..13ed8f1 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/viewModel/StatsViewModel.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/viewModel/StatsViewModel.kt
@@ -67,8 +67,10 @@ class StatsViewModel(
private val yearDayFormatter = DateTimeFormatter.ofPattern("d MMM")
+ private val lastWeekStatsFlow = statRepository.getLastNDaysStats(7)
+
val lastWeekSummaryChartData: StateFlow>>> =
- statRepository.getLastNDaysStatsSummary(7)
+ lastWeekStatsFlow
.map { list ->
// reversing is required because we need ascending order while the DB returns descending order
val reversed = list.reversed()
@@ -78,7 +80,7 @@ class StatsViewModel(
Locale.getDefault()
)
}
- val values = reversed.map { it.focusTime }
+ val values = reversed.map { it.totalFocusTime() }
lastWeekSummary.first.runTransaction {
columnSeries { series(values) }
extras { it[lastWeekSummary.second] = keys }
@@ -92,29 +94,57 @@ class StatsViewModel(
initialValue = lastWeekSummary
)
- val lastWeekAverageFocusTimes: StateFlow> =
+ val lastWeekStats: StateFlow>>> =
+ lastWeekStatsFlow
+ .map { value ->
+ value.reversed().map {
+ Pair(
+ it.date.dayOfWeek.getDisplayName(
+ TextStyle.NARROW,
+ Locale.getDefault()
+ ),
+ listOf(
+ it.focusTimeQ1,
+ it.focusTimeQ2,
+ it.focusTimeQ3,
+ it.focusTimeQ4
+ )
+ )
+ }
+ }
+ .flowOn(Dispatchers.IO)
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5000),
+ initialValue = emptyList()
+ )
+
+ val lastWeekAverageFocusTimes: StateFlow, Long>> =
statRepository.getLastNDaysAverageFocusTimes(7)
.map {
- listOf(
- it?.focusTimeQ1?.toInt() ?: 0,
- it?.focusTimeQ2?.toInt() ?: 0,
- it?.focusTimeQ3?.toInt() ?: 0,
- it?.focusTimeQ4?.toInt() ?: 0
+ Pair(
+ listOf(
+ it?.focusTimeQ1 ?: 0L,
+ it?.focusTimeQ2 ?: 0L,
+ it?.focusTimeQ3 ?: 0L,
+ it?.focusTimeQ4 ?: 0L
+ ),
+ it?.breakTime ?: 0L
)
}
.flowOn(Dispatchers.IO)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
- initialValue = listOf(0, 0, 0, 0)
+ initialValue = Pair(listOf(0L, 0L, 0L, 0L), 0L)
)
val lastMonthSummaryChartData: StateFlow>>> =
- statRepository.getLastNDaysStatsSummary(30)
+ statRepository.getLastNDaysStats(30)
.map { list ->
val reversed = list.reversed()
val keys = reversed.map { it.date.dayOfMonth.toString() }
- val values = reversed.map { it.focusTime }
+ val values = reversed.map { it.totalFocusTime() }
lastMonthSummary.first.runTransaction {
columnSeries { series(values) }
extras { it[lastMonthSummary.second] = keys }
@@ -146,11 +176,11 @@ class StatsViewModel(
)
val lastYearSummaryChartData: StateFlow>>> =
- statRepository.getLastNDaysStatsSummary(365)
+ statRepository.getLastNDaysStats(365)
.map { list ->
val reversed = list.reversed()
val keys = reversed.map { it.date.format(yearDayFormatter) }
- val values = reversed.map { it.focusTime }
+ val values = reversed.map { it.totalFocusTime() }
lastYearSummary.first.runTransaction {
lineSeries { series(values) }
extras { it[lastYearSummary.second] = keys }
@@ -195,13 +225,11 @@ class StatsViewModel(
(1 * 60 * 60 * 1000L..3 * 60 * 60 * 1000L).random(),
(0..3 * 60 * 60 * 1000L).random(),
(0..1 * 60 * 60 * 1000L).random(),
- 0
+ (0..100 * 60 * 1000L).random()
)
)
it = it.plusDays(1)
}
-
- statRepository.addBreakTime((0..30 * 60 * 1000L).random())
}
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3755e19..24df1ec 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -113,4 +113,5 @@
Automatically lock your device after a timeout, while keeping the AOD visible
Timer reset
Undo
+ Focus-break ratio
\ No newline at end of file