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 2ad928e..2110244 100644 --- a/app/src/main/java/org/nsh07/pomodoro/data/Stat.kt +++ b/app/src/main/java/org/nsh07/pomodoro/data/Stat.kt @@ -25,7 +25,9 @@ data class Stat( val focusTimeQ3: Long, val focusTimeQ4: Long, val breakTime: Long -) +) { + fun totalFocusTime() = focusTimeQ1 + focusTimeQ2 + focusTimeQ3 + focusTimeQ4 +} data class StatSummary( val date: LocalDate, @@ -38,4 +40,6 @@ data class StatFocusTime( val focusTimeQ2: Long, val focusTimeQ3: Long, val focusTimeQ4: Long -) \ No newline at end of file +) { + fun total() = focusTimeQ1 + focusTimeQ2 + focusTimeQ3 + focusTimeQ4 +} \ 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 be71237..5c9ad6c 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 @@ -33,7 +33,6 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -48,6 +47,7 @@ import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter @@ -56,6 +56,7 @@ import com.patrykandpatrick.vico.core.common.data.ExtraStore import kotlinx.coroutines.runBlocking import org.nsh07.pomodoro.R import org.nsh07.pomodoro.data.Stat +import org.nsh07.pomodoro.data.StatFocusTime import org.nsh07.pomodoro.ui.statsScreen.viewModel.StatsViewModel import org.nsh07.pomodoro.ui.theme.AppFonts.openRundeClock import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar @@ -66,13 +67,20 @@ fun StatsScreenRoot( modifier: Modifier = Modifier, viewModel: StatsViewModel = viewModel(factory = StatsViewModel.Factory) ) { - val todayStat by viewModel.todayStat.collectAsState(null) + val todayStat by viewModel.todayStat.collectAsStateWithLifecycle(null) + val lastWeekAverageFocusTimes by viewModel + .lastWeekAverageFocusTimes.collectAsStateWithLifecycle(null) + val lastMonthAverageFocusTimes by viewModel + .lastMonthAverageFocusTimes.collectAsStateWithLifecycle(null) + StatsScreen( lastWeekSummaryChartData = remember { viewModel.lastWeekSummaryChartData }, lastWeekSummaryAnalysisModelProducer = remember { viewModel.lastWeekSummaryAnalysisModelProducer }, lastMonthSummaryChartData = remember { viewModel.lastMonthSummaryChartData }, lastMonthSummaryAnalysisModelProducer = remember { viewModel.lastMonthSummaryAnalysisModelProducer }, todayStat = todayStat, + lastWeekAverageFocusTimes = lastWeekAverageFocusTimes, + lastMonthAverageFocusTimes = lastMonthAverageFocusTimes, modifier = modifier ) } @@ -85,6 +93,8 @@ fun StatsScreen( lastMonthSummaryChartData: Pair>>, lastMonthSummaryAnalysisModelProducer: CartesianChartModelProducer, todayStat: Stat?, + lastWeekAverageFocusTimes: StatFocusTime?, + lastMonthAverageFocusTimes: StatFocusTime?, modifier: Modifier = Modifier ) { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() @@ -143,14 +153,9 @@ fun StatsScreen( color = colorScheme.onPrimaryContainer ) Text( - if (todayStat != null) remember(todayStat) { - millisecondsToHoursMinutes( - todayStat.focusTimeQ1 + - todayStat.focusTimeQ2 + - todayStat.focusTimeQ3 + - todayStat.focusTimeQ4 - ) - } else "0h 0m", + remember(todayStat) { + millisecondsToHoursMinutes(todayStat?.totalFocusTime() ?: 0) + }, style = typography.displaySmall, fontFamily = openRundeClock, color = colorScheme.onPrimaryContainer @@ -173,9 +178,9 @@ fun StatsScreen( color = colorScheme.onTertiaryContainer ) Text( - if (todayStat != null) remember(todayStat) { - millisecondsToHoursMinutes(todayStat.breakTime) - } else "0h 0m", + remember(todayStat) { + millisecondsToHoursMinutes(todayStat?.breakTime ?: 0) + }, style = typography.displaySmall, fontFamily = openRundeClock, color = colorScheme.onTertiaryContainer @@ -194,6 +199,26 @@ fun StatsScreen( .padding(horizontal = 16.dp) ) } + item { + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + Text( + millisecondsToHoursMinutes(lastWeekAverageFocusTimes?.total() ?: 0), + style = typography.displaySmall, + fontFamily = openRundeClock + ) + Text( + "focus per day (avg)", + style = typography.titleSmall, + modifier = Modifier.padding(bottom = 6.3.dp) + ) + } + } item { TimeColumnChart( lastWeekSummaryChartData.first, @@ -246,6 +271,26 @@ fun StatsScreen( .padding(horizontal = 16.dp) ) } + item { + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + Text( + millisecondsToHoursMinutes(lastMonthAverageFocusTimes?.total() ?: 0), + style = typography.displaySmall, + fontFamily = openRundeClock + ) + Text( + "focus per day (avg)", + style = typography.titleSmall, + modifier = Modifier.padding(bottom = 6.3.dp) + ) + } + } item { TimeColumnChart( lastMonthSummaryChartData.first, @@ -315,6 +360,8 @@ fun StatsScreenPreview() { modelProducer, Pair(modelProducer, ExtraStore.Key()), modelProducer, + null, + null, null ) } 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 de12813..73f4f8e 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 @@ -21,18 +21,20 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import org.nsh07.pomodoro.TomatoApplication import org.nsh07.pomodoro.data.StatRepository -import java.time.format.DateTimeFormatter +import java.time.format.TextStyle +import java.util.Locale class StatsViewModel( statRepository: StatRepository ) : ViewModel() { - private val dayFormatter = DateTimeFormatter.ofPattern("E") val todayStat = statRepository.getTodayStat().distinctUntilChanged() private val lastWeekStatsSummary = statRepository.getLastNDaysStatsSummary(7) - private val lastWeekAverageFocusTimes = statRepository.getLastNDaysAverageFocusTimes(7) + val lastWeekAverageFocusTimes = + statRepository.getLastNDaysAverageFocusTimes(7).distinctUntilChanged() private val lastMonthStatsSummary = statRepository.getLastNDaysStatsSummary(30) - private val lastMonthAverageFocusTimes = statRepository.getLastNDaysAverageFocusTimes(30) + val lastMonthAverageFocusTimes = + statRepository.getLastNDaysAverageFocusTimes(30).distinctUntilChanged() val lastWeekSummaryChartData = Pair(CartesianChartModelProducer(), ExtraStore.Key>()) @@ -48,7 +50,12 @@ class StatsViewModel( .collect { list -> // reversing is required because we need ascending order while the DB returns descending order val reversed = list.reversed() - val keys = reversed.map { it.date.format(dayFormatter) } + val keys = reversed.map { + it.date.dayOfWeek.getDisplayName( + TextStyle.NARROW, + Locale.getDefault() + ) + } val values = reversed.map { it.focusTime } lastWeekSummaryChartData.first.runTransaction { columnSeries { series(values) } diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/theme/Type.kt b/app/src/main/java/org/nsh07/pomodoro/ui/theme/Type.kt index 6fd8593..8231eb0 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/theme/Type.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/theme/Type.kt @@ -39,6 +39,12 @@ val Typography = Typography( fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp, + ), + titleSmall = TextStyle( + fontFamily = robotoFlexTitle, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.1.sp ) )