feat(stats): implement showing last year stats in a line chart
This commit is contained in:
@@ -78,34 +78,18 @@ fun StatsScreenRoot(
|
|||||||
val lastMonthSummaryChartData by viewModel.lastMonthSummaryChartData.collectAsStateWithLifecycle()
|
val lastMonthSummaryChartData by viewModel.lastMonthSummaryChartData.collectAsStateWithLifecycle()
|
||||||
val lastMonthAnalysisValues by viewModel.lastMonthAverageFocusTimes.collectAsStateWithLifecycle()
|
val lastMonthAnalysisValues by viewModel.lastMonthAverageFocusTimes.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
val lastWeekSummaryAnalysisModelProducer = remember { CartesianChartModelProducer() }
|
val lastYearSummaryChartData by viewModel.lastYearSummaryChartData.collectAsStateWithLifecycle()
|
||||||
val lastMonthSummaryAnalysisModelProducer = remember { CartesianChartModelProducer() }
|
val lastYearAnalysisValues by viewModel.lastYearAverageFocusTimes.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
LaunchedEffect(lastWeekAnalysisValues) {
|
|
||||||
lastWeekSummaryAnalysisModelProducer.runTransaction {
|
|
||||||
columnSeries {
|
|
||||||
series(lastWeekAnalysisValues)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(lastMonthAnalysisValues) {
|
|
||||||
lastMonthSummaryAnalysisModelProducer.runTransaction {
|
|
||||||
columnSeries {
|
|
||||||
series(lastMonthAnalysisValues)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StatsScreen(
|
StatsScreen(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
lastWeekSummaryChartData = lastWeekSummaryChartData,
|
lastWeekSummaryChartData = lastWeekSummaryChartData,
|
||||||
lastWeekSummaryAnalysisModelProducer = lastWeekSummaryAnalysisModelProducer,
|
|
||||||
lastMonthSummaryChartData = lastMonthSummaryChartData,
|
lastMonthSummaryChartData = lastMonthSummaryChartData,
|
||||||
lastMonthSummaryAnalysisModelProducer = lastMonthSummaryAnalysisModelProducer,
|
lastYearSummaryChartData = lastYearSummaryChartData,
|
||||||
todayStat = todayStat,
|
todayStat = todayStat,
|
||||||
lastWeekAverageFocusTimes = lastWeekAnalysisValues,
|
lastWeekAverageFocusTimes = lastWeekAnalysisValues,
|
||||||
lastMonthAverageFocusTimes = lastMonthAnalysisValues,
|
lastMonthAverageFocusTimes = lastMonthAnalysisValues,
|
||||||
|
lastYearAverageFocusTimes = lastYearAnalysisValues,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -115,12 +99,12 @@ fun StatsScreenRoot(
|
|||||||
fun StatsScreen(
|
fun StatsScreen(
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
lastWeekSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
lastWeekSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
||||||
lastWeekSummaryAnalysisModelProducer: CartesianChartModelProducer,
|
|
||||||
lastMonthSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
lastMonthSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
||||||
lastMonthSummaryAnalysisModelProducer: CartesianChartModelProducer,
|
lastYearSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
||||||
todayStat: Stat?,
|
todayStat: Stat?,
|
||||||
lastWeekAverageFocusTimes: List<Int>,
|
lastWeekAverageFocusTimes: List<Int>,
|
||||||
lastMonthAverageFocusTimes: List<Int>,
|
lastMonthAverageFocusTimes: List<Int>,
|
||||||
|
lastYearAverageFocusTimes: List<Int>,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||||
@@ -128,6 +112,25 @@ fun StatsScreen(
|
|||||||
var lastWeekStatExpanded by rememberSaveable { mutableStateOf(false) }
|
var lastWeekStatExpanded by rememberSaveable { mutableStateOf(false) }
|
||||||
var lastMonthStatExpanded by rememberSaveable { mutableStateOf(false) }
|
var lastMonthStatExpanded by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val lastWeekSummaryAnalysisModelProducer = remember { CartesianChartModelProducer() }
|
||||||
|
val lastMonthSummaryAnalysisModelProducer = remember { CartesianChartModelProducer() }
|
||||||
|
|
||||||
|
LaunchedEffect(lastWeekAverageFocusTimes) {
|
||||||
|
lastWeekSummaryAnalysisModelProducer.runTransaction {
|
||||||
|
columnSeries {
|
||||||
|
series(lastWeekAverageFocusTimes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(lastMonthAverageFocusTimes) {
|
||||||
|
lastMonthSummaryAnalysisModelProducer.runTransaction {
|
||||||
|
columnSeries {
|
||||||
|
series(lastMonthAverageFocusTimes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
@@ -371,8 +374,51 @@ fun StatsScreen(
|
|||||||
modifier = Modifier.padding(horizontal = 32.dp)
|
modifier = Modifier.padding(horizontal = 32.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(16.dp))
|
|
||||||
}
|
}
|
||||||
|
item { Spacer(Modifier) }
|
||||||
|
item {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.last_year),
|
||||||
|
style = typography.headlineSmall,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.Bottom,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
millisecondsToHoursMinutes(
|
||||||
|
remember(lastYearAverageFocusTimes) {
|
||||||
|
lastYearAverageFocusTimes.sum().toLong()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
style = typography.displaySmall,
|
||||||
|
fontFamily = openRundeClock
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.focus_per_day_avg),
|
||||||
|
style = typography.titleSmall,
|
||||||
|
modifier = Modifier.padding(bottom = 6.3.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
TimeLineChart(
|
||||||
|
lastYearSummaryChartData.first,
|
||||||
|
modifier = Modifier.padding(start = 16.dp),
|
||||||
|
xValueFormatter = CartesianValueFormatter { context, x, _ ->
|
||||||
|
context.model.extraStore[lastYearSummaryChartData.second][x.toInt()]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item { Spacer(Modifier.height(16.dp)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,11 +444,11 @@ fun StatsScreenPreview() {
|
|||||||
StatsScreen(
|
StatsScreen(
|
||||||
PaddingValues(),
|
PaddingValues(),
|
||||||
Pair(modelProducer, keys),
|
Pair(modelProducer, keys),
|
||||||
modelProducer,
|
|
||||||
Pair(modelProducer, keys),
|
Pair(modelProducer, keys),
|
||||||
modelProducer,
|
Pair(modelProducer, keys),
|
||||||
null,
|
null,
|
||||||
listOf(0, 0, 0, 0),
|
listOf(0, 0, 0, 0),
|
||||||
|
listOf(0, 0, 0, 0),
|
||||||
listOf(0, 0, 0, 0)
|
listOf(0, 0, 0, 0)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ import org.nsh07.pomodoro.utils.millisecondsToMinutes
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TimeLineChart(
|
fun TimeLineChart(
|
||||||
modelProducer: CartesianChartModelProducer,
|
modelProducer: CartesianChartModelProducer,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
thickness: Float = 2f,
|
thickness: Float = 2f,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import androidx.lifecycle.viewmodel.initializer
|
|||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
||||||
|
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
|
||||||
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@@ -23,6 +24,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import org.nsh07.pomodoro.TomatoApplication
|
import org.nsh07.pomodoro.TomatoApplication
|
||||||
import org.nsh07.pomodoro.data.StatRepository
|
import org.nsh07.pomodoro.data.StatRepository
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.time.format.TextStyle
|
import java.time.format.TextStyle
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -34,9 +36,12 @@ class StatsViewModel(
|
|||||||
|
|
||||||
private val lastWeekSummary =
|
private val lastWeekSummary =
|
||||||
Pair(CartesianChartModelProducer(), ExtraStore.Key<List<String>>())
|
Pair(CartesianChartModelProducer(), ExtraStore.Key<List<String>>())
|
||||||
|
|
||||||
private val lastMonthSummary =
|
private val lastMonthSummary =
|
||||||
Pair(CartesianChartModelProducer(), ExtraStore.Key<List<String>>())
|
Pair(CartesianChartModelProducer(), ExtraStore.Key<List<String>>())
|
||||||
|
private val lastYearSummary =
|
||||||
|
Pair(CartesianChartModelProducer(), ExtraStore.Key<List<String>>())
|
||||||
|
|
||||||
|
private val yearDayFormatter = DateTimeFormatter.ofPattern("d MMM")
|
||||||
|
|
||||||
val lastWeekSummaryChartData: StateFlow<Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>> =
|
val lastWeekSummaryChartData: StateFlow<Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>> =
|
||||||
statRepository.getLastNDaysStatsSummary(7)
|
statRepository.getLastNDaysStatsSummary(7)
|
||||||
@@ -112,6 +117,40 @@ class StatsViewModel(
|
|||||||
initialValue = listOf(0, 0, 0, 0)
|
initialValue = listOf(0, 0, 0, 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val lastYearSummaryChartData: StateFlow<Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>> =
|
||||||
|
statRepository.getLastNDaysStatsSummary(365)
|
||||||
|
.map { list ->
|
||||||
|
val reversed = list.reversed()
|
||||||
|
val keys = reversed.map { it.date.format(yearDayFormatter) }
|
||||||
|
val values = reversed.map { it.focusTime }
|
||||||
|
lastYearSummary.first.runTransaction {
|
||||||
|
lineSeries { series(values) }
|
||||||
|
extras { it[lastYearSummary.second] = keys }
|
||||||
|
}
|
||||||
|
lastYearSummary
|
||||||
|
}
|
||||||
|
.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.WhileSubscribed(5000),
|
||||||
|
initialValue = lastYearSummary
|
||||||
|
)
|
||||||
|
|
||||||
|
val lastYearAverageFocusTimes: StateFlow<List<Int>> =
|
||||||
|
statRepository.getLastNDaysAverageFocusTimes(365)
|
||||||
|
.map {
|
||||||
|
listOf(
|
||||||
|
it?.focusTimeQ1?.toInt() ?: 0,
|
||||||
|
it?.focusTimeQ2?.toInt() ?: 0,
|
||||||
|
it?.focusTimeQ3?.toInt() ?: 0,
|
||||||
|
it?.focusTimeQ4?.toInt() ?: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.WhileSubscribed(5000),
|
||||||
|
initialValue = listOf(0, 0, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
|
|||||||
@@ -56,4 +56,5 @@
|
|||||||
<string name="up_next">Up next</string>
|
<string name="up_next">Up next</string>
|
||||||
<string name="timer">Timer</string>
|
<string name="timer">Timer</string>
|
||||||
<string name="timer_progress">Timer progress</string>
|
<string name="timer_progress">Timer progress</string>
|
||||||
|
<string name="last_year">Last year</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user