refactor(stats): refactor flow collection to improve performance
This commit is contained in:
@@ -35,6 +35,7 @@ import androidx.compose.material3.Text
|
||||
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
|
||||
@@ -56,10 +57,8 @@ 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 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
|
||||
@@ -72,20 +71,41 @@ fun StatsScreenRoot(
|
||||
viewModel: StatsViewModel = viewModel(factory = StatsViewModel.Factory)
|
||||
) {
|
||||
val todayStat by viewModel.todayStat.collectAsStateWithLifecycle(null)
|
||||
val lastWeekAverageFocusTimes by viewModel
|
||||
.lastWeekAverageFocusTimes.collectAsStateWithLifecycle(null)
|
||||
val lastMonthAverageFocusTimes by viewModel
|
||||
.lastMonthAverageFocusTimes.collectAsStateWithLifecycle(null)
|
||||
|
||||
val lastWeekSummaryChartData by viewModel.lastWeekSummaryChartData.collectAsStateWithLifecycle()
|
||||
val lastWeekAnalysisValues by viewModel.lastWeekAverageFocusTimes.collectAsStateWithLifecycle()
|
||||
|
||||
val lastMonthSummaryChartData by viewModel.lastMonthSummaryChartData.collectAsStateWithLifecycle()
|
||||
val lastMonthAnalysisValues by viewModel.lastMonthAverageFocusTimes.collectAsStateWithLifecycle()
|
||||
|
||||
val lastWeekSummaryAnalysisModelProducer = remember { CartesianChartModelProducer() }
|
||||
val lastMonthSummaryAnalysisModelProducer = remember { CartesianChartModelProducer() }
|
||||
|
||||
LaunchedEffect(lastWeekAnalysisValues) {
|
||||
lastWeekSummaryAnalysisModelProducer.runTransaction {
|
||||
columnSeries {
|
||||
series(lastWeekAnalysisValues)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(lastMonthAnalysisValues) {
|
||||
lastMonthSummaryAnalysisModelProducer.runTransaction {
|
||||
columnSeries {
|
||||
series(lastMonthAnalysisValues)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatsScreen(
|
||||
contentPadding = contentPadding,
|
||||
lastWeekSummaryChartData = remember { viewModel.lastWeekSummaryChartData },
|
||||
lastWeekSummaryAnalysisModelProducer = remember { viewModel.lastWeekSummaryAnalysisModelProducer },
|
||||
lastMonthSummaryChartData = remember { viewModel.lastMonthSummaryChartData },
|
||||
lastMonthSummaryAnalysisModelProducer = remember { viewModel.lastMonthSummaryAnalysisModelProducer },
|
||||
lastWeekSummaryChartData = lastWeekSummaryChartData,
|
||||
lastWeekSummaryAnalysisModelProducer = lastWeekSummaryAnalysisModelProducer,
|
||||
lastMonthSummaryChartData = lastMonthSummaryChartData,
|
||||
lastMonthSummaryAnalysisModelProducer = lastMonthSummaryAnalysisModelProducer,
|
||||
todayStat = todayStat,
|
||||
lastWeekAverageFocusTimes = lastWeekAverageFocusTimes,
|
||||
lastMonthAverageFocusTimes = lastMonthAverageFocusTimes,
|
||||
lastWeekAverageFocusTimes = lastWeekAnalysisValues,
|
||||
lastMonthAverageFocusTimes = lastMonthAnalysisValues,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
@@ -99,8 +119,8 @@ fun StatsScreen(
|
||||
lastMonthSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
||||
lastMonthSummaryAnalysisModelProducer: CartesianChartModelProducer,
|
||||
todayStat: Stat?,
|
||||
lastWeekAverageFocusTimes: StatFocusTime?,
|
||||
lastMonthAverageFocusTimes: StatFocusTime?,
|
||||
lastWeekAverageFocusTimes: List<Int>,
|
||||
lastMonthAverageFocusTimes: List<Int>,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
@@ -218,7 +238,11 @@ fun StatsScreen(
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
millisecondsToHoursMinutes(lastWeekAverageFocusTimes?.total() ?: 0),
|
||||
millisecondsToHoursMinutes(
|
||||
remember(lastWeekAverageFocusTimes) {
|
||||
lastWeekAverageFocusTimes.sum().toLong()
|
||||
}
|
||||
),
|
||||
style = typography.displaySmall,
|
||||
fontFamily = openRundeClock
|
||||
)
|
||||
@@ -290,7 +314,11 @@ fun StatsScreen(
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
millisecondsToHoursMinutes(lastMonthAverageFocusTimes?.total() ?: 0),
|
||||
millisecondsToHoursMinutes(
|
||||
remember(lastMonthAverageFocusTimes) {
|
||||
lastMonthAverageFocusTimes.sum().toLong()
|
||||
}
|
||||
),
|
||||
style = typography.displaySmall,
|
||||
fontFamily = openRundeClock
|
||||
)
|
||||
@@ -356,23 +384,25 @@ fun StatsScreen(
|
||||
@Composable
|
||||
fun StatsScreenPreview() {
|
||||
val modelProducer = remember { CartesianChartModelProducer() }
|
||||
val keys = remember { ExtraStore.Key<List<String>>() }
|
||||
|
||||
runBlocking {
|
||||
LaunchedEffect(Unit) {
|
||||
modelProducer.runTransaction {
|
||||
columnSeries {
|
||||
series(5, 6, 5, 2, 11, 8, 5, 2, 15, 11, 8, 13, 12, 10, 2, 7)
|
||||
}
|
||||
extras { it[keys] = listOf("M", "T", "W", "T", "F", "S", "S") }
|
||||
}
|
||||
}
|
||||
|
||||
StatsScreen(
|
||||
PaddingValues(),
|
||||
Pair(modelProducer, ExtraStore.Key()),
|
||||
Pair(modelProducer, keys),
|
||||
modelProducer,
|
||||
Pair(modelProducer, ExtraStore.Key()),
|
||||
Pair(modelProducer, keys),
|
||||
modelProducer,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
listOf(0, 0, 0, 0),
|
||||
listOf(0, 0, 0, 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,11 @@ import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
||||
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.nsh07.pomodoro.TomatoApplication
|
||||
import org.nsh07.pomodoro.data.StatRepository
|
||||
import java.time.format.TextStyle
|
||||
@@ -29,83 +31,86 @@ class StatsViewModel(
|
||||
) : ViewModel() {
|
||||
|
||||
val todayStat = statRepository.getTodayStat().distinctUntilChanged()
|
||||
private val lastWeekStatsSummary = statRepository.getLastNDaysStatsSummary(7)
|
||||
val lastWeekAverageFocusTimes =
|
||||
statRepository.getLastNDaysAverageFocusTimes(7).distinctUntilChanged()
|
||||
private val lastMonthStatsSummary = statRepository.getLastNDaysStatsSummary(30)
|
||||
val lastMonthAverageFocusTimes =
|
||||
statRepository.getLastNDaysAverageFocusTimes(30).distinctUntilChanged()
|
||||
|
||||
val lastWeekSummaryChartData =
|
||||
private val lastWeekSummary =
|
||||
Pair(CartesianChartModelProducer(), ExtraStore.Key<List<String>>())
|
||||
val lastWeekSummaryAnalysisModelProducer = CartesianChartModelProducer()
|
||||
|
||||
val lastMonthSummaryChartData =
|
||||
private val lastMonthSummary =
|
||||
Pair(CartesianChartModelProducer(), ExtraStore.Key<List<String>>())
|
||||
val lastMonthSummaryAnalysisModelProducer = CartesianChartModelProducer()
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
lastWeekStatsSummary
|
||||
.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.dayOfWeek.getDisplayName(
|
||||
TextStyle.NARROW,
|
||||
Locale.getDefault()
|
||||
)
|
||||
}
|
||||
val values = reversed.map { it.focusTime }
|
||||
lastWeekSummaryChartData.first.runTransaction {
|
||||
columnSeries { series(values) }
|
||||
extras { it[lastWeekSummaryChartData.second] = keys }
|
||||
}
|
||||
val lastWeekSummaryChartData: StateFlow<Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>> =
|
||||
statRepository.getLastNDaysStatsSummary(7)
|
||||
.map { 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.dayOfWeek.getDisplayName(
|
||||
TextStyle.NARROW,
|
||||
Locale.getDefault()
|
||||
)
|
||||
}
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
lastWeekAverageFocusTimes
|
||||
.collect {
|
||||
lastWeekSummaryAnalysisModelProducer.runTransaction {
|
||||
columnSeries {
|
||||
series(
|
||||
it?.focusTimeQ1 ?: 0,
|
||||
it?.focusTimeQ2 ?: 0,
|
||||
it?.focusTimeQ3 ?: 0,
|
||||
it?.focusTimeQ4 ?: 0
|
||||
)
|
||||
}
|
||||
}
|
||||
val values = reversed.map { it.focusTime }
|
||||
lastWeekSummary.first.runTransaction {
|
||||
columnSeries { series(values) }
|
||||
extras { it[lastWeekSummary.second] = keys }
|
||||
}
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
lastMonthStatsSummary
|
||||
.collect { list ->
|
||||
val reversed = list.reversed()
|
||||
val keys = reversed.map { it.date.dayOfMonth.toString() }
|
||||
val values = reversed.map { it.focusTime }
|
||||
lastMonthSummaryChartData.first.runTransaction {
|
||||
columnSeries { series(values) }
|
||||
extras { it[lastMonthSummaryChartData.second] = keys }
|
||||
}
|
||||
lastWeekSummary
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000),
|
||||
initialValue = lastWeekSummary
|
||||
)
|
||||
|
||||
val lastWeekAverageFocusTimes: StateFlow<List<Int>> =
|
||||
statRepository.getLastNDaysAverageFocusTimes(7)
|
||||
.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)
|
||||
)
|
||||
|
||||
val lastMonthSummaryChartData: StateFlow<Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>> =
|
||||
statRepository.getLastNDaysStatsSummary(30)
|
||||
.map { list ->
|
||||
val reversed = list.reversed()
|
||||
val keys = reversed.map { it.date.dayOfMonth.toString() }
|
||||
val values = reversed.map { it.focusTime }
|
||||
lastMonthSummary.first.runTransaction {
|
||||
columnSeries { series(values) }
|
||||
extras { it[lastMonthSummary.second] = keys }
|
||||
}
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
lastMonthAverageFocusTimes
|
||||
.collect {
|
||||
lastMonthSummaryAnalysisModelProducer.runTransaction {
|
||||
columnSeries {
|
||||
series(
|
||||
it?.focusTimeQ1 ?: 0,
|
||||
it?.focusTimeQ2 ?: 0,
|
||||
it?.focusTimeQ3 ?: 0,
|
||||
it?.focusTimeQ4 ?: 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastMonthSummary
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000),
|
||||
initialValue = lastMonthSummary
|
||||
)
|
||||
|
||||
val lastMonthAverageFocusTimes: StateFlow<List<Int>> =
|
||||
statRepository.getLastNDaysAverageFocusTimes(30)
|
||||
.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 {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
|
||||
Reference in New Issue
Block a user