feat(stats): basic shared element transition for last week screen
This commit is contained in:
@@ -19,12 +19,16 @@ package org.nsh07.pomodoro.ui.statsScreen
|
|||||||
|
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
|
import androidx.compose.animation.SharedTransitionLayout
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.animation.unveilIn
|
import androidx.compose.animation.unveilIn
|
||||||
import androidx.compose.animation.veilOut
|
import androidx.compose.animation.veilOut
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -99,6 +103,8 @@ fun StatsScreen(
|
|||||||
generateSampleData: () -> Unit,
|
generateSampleData: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val colorScheme = colorScheme
|
||||||
|
|
||||||
val hoursFormat = stringResource(R.string.hours_format)
|
val hoursFormat = stringResource(R.string.hours_format)
|
||||||
val hoursMinutesFormat = stringResource(R.string.hours_and_minutes_format)
|
val hoursMinutesFormat = stringResource(R.string.hours_and_minutes_format)
|
||||||
val minutesFormat = stringResource(R.string.minutes_format)
|
val minutesFormat = stringResource(R.string.minutes_format)
|
||||||
@@ -107,56 +113,58 @@ fun StatsScreen(
|
|||||||
val axisTypeface = remember { resolver.resolve(googleFlex400).value as Typeface }
|
val axisTypeface = remember { resolver.resolve(googleFlex400).value as Typeface }
|
||||||
val markerTypeface = remember { resolver.resolve(googleFlex600).value as Typeface }
|
val markerTypeface = remember { resolver.resolve(googleFlex600).value as Typeface }
|
||||||
|
|
||||||
NavDisplay(
|
SharedTransitionLayout {
|
||||||
backStack = backStack,
|
NavDisplay(
|
||||||
onBack = backStack::removeLastOrNull,
|
backStack = backStack,
|
||||||
transitionSpec = {
|
onBack = backStack::removeLastOrNull,
|
||||||
unveilIn().togetherWith(veilOut())
|
transitionSpec = {
|
||||||
},
|
fadeIn().togetherWith(veilOut(targetColor = colorScheme.surfaceDim))
|
||||||
popTransitionSpec = {
|
},
|
||||||
unveilIn().togetherWith(veilOut())
|
popTransitionSpec = {
|
||||||
},
|
unveilIn(initialColor = colorScheme.surfaceDim).togetherWith(fadeOut())
|
||||||
predictivePopTransitionSpec = {
|
},
|
||||||
unveilIn().togetherWith(veilOut())
|
predictivePopTransitionSpec = {
|
||||||
},
|
unveilIn(initialColor = colorScheme.surfaceDim).togetherWith(fadeOut())
|
||||||
entryProvider = entryProvider {
|
},
|
||||||
entry<Screen.Stats.Main> {
|
entryProvider = entryProvider {
|
||||||
StatsMainScreen(
|
entry<Screen.Stats.Main> {
|
||||||
contentPadding = contentPadding,
|
StatsMainScreen(
|
||||||
lastWeekSummaryChartData = lastWeekSummaryChartData,
|
contentPadding = contentPadding,
|
||||||
lastMonthSummaryChartData = lastMonthSummaryChartData,
|
lastWeekSummaryChartData = lastWeekSummaryChartData,
|
||||||
lastYearSummaryChartData = lastYearSummaryChartData,
|
lastMonthSummaryChartData = lastMonthSummaryChartData,
|
||||||
todayStat = todayStat,
|
lastYearSummaryChartData = lastYearSummaryChartData,
|
||||||
lastWeekAverageFocusTimes = lastWeekAverageFocusTimes,
|
todayStat = todayStat,
|
||||||
lastMonthAverageFocusTimes = lastMonthAverageFocusTimes,
|
lastWeekAverageFocusTimes = lastWeekAverageFocusTimes,
|
||||||
lastYearAverageFocusTimes = lastYearAverageFocusTimes,
|
lastMonthAverageFocusTimes = lastMonthAverageFocusTimes,
|
||||||
generateSampleData = generateSampleData,
|
lastYearAverageFocusTimes = lastYearAverageFocusTimes,
|
||||||
hoursFormat = hoursFormat,
|
generateSampleData = generateSampleData,
|
||||||
hoursMinutesFormat = hoursMinutesFormat,
|
hoursFormat = hoursFormat,
|
||||||
minutesFormat = minutesFormat,
|
hoursMinutesFormat = hoursMinutesFormat,
|
||||||
axisTypeface = axisTypeface,
|
minutesFormat = minutesFormat,
|
||||||
markerTypeface = markerTypeface,
|
axisTypeface = axisTypeface,
|
||||||
onNavigate = {
|
markerTypeface = markerTypeface,
|
||||||
if (backStack.size < 2) backStack.add(it)
|
onNavigate = {
|
||||||
else backStack[backStack.lastIndex] = it
|
if (backStack.size < 2) backStack.add(it)
|
||||||
},
|
else backStack[backStack.lastIndex] = it
|
||||||
modifier = modifier
|
},
|
||||||
)
|
modifier = modifier
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
entry<Screen.Stats.LastWeek> {
|
entry<Screen.Stats.LastWeek> {
|
||||||
LastWeekScreen(
|
LastWeekScreen(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
lastWeekAverageFocusTimes = lastWeekAverageFocusTimes,
|
lastWeekAverageFocusTimes = lastWeekAverageFocusTimes,
|
||||||
onBack = backStack::removeLastOrNull,
|
onBack = backStack::removeLastOrNull,
|
||||||
hoursMinutesFormat = hoursMinutesFormat,
|
hoursMinutesFormat = hoursMinutesFormat,
|
||||||
lastWeekSummaryChartData = lastWeekSummaryChartData,
|
lastWeekSummaryChartData = lastWeekSummaryChartData,
|
||||||
hoursFormat = hoursFormat,
|
hoursFormat = hoursFormat,
|
||||||
minutesFormat = minutesFormat,
|
minutesFormat = minutesFormat,
|
||||||
axisTypeface = axisTypeface,
|
axisTypeface = axisTypeface,
|
||||||
markerTypeface = markerTypeface
|
markerTypeface = markerTypeface
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.nsh07.pomodoro.ui.statsScreen.components
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibilityScope
|
||||||
|
import androidx.compose.animation.BoundsTransform
|
||||||
|
import androidx.compose.animation.EnterTransition
|
||||||
|
import androidx.compose.animation.ExitTransition
|
||||||
|
import androidx.compose.animation.SharedTransitionDefaults
|
||||||
|
import androidx.compose.animation.SharedTransitionScope
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.navigation3.ui.LocalNavAnimatedContentScope
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
|
@Composable
|
||||||
|
fun Modifier.sharedBoundsReveal(
|
||||||
|
sharedContentState: SharedTransitionScope.SharedContentState,
|
||||||
|
sharedTransitionScope: SharedTransitionScope,
|
||||||
|
animatedVisibilityScope: AnimatedVisibilityScope = LocalNavAnimatedContentScope.current,
|
||||||
|
boundsTransform: BoundsTransform = SharedTransitionDefaults.BoundsTransform,
|
||||||
|
enter: EnterTransition = EnterTransition.None,
|
||||||
|
exit: ExitTransition = ExitTransition.None,
|
||||||
|
resizeMode: SharedTransitionScope.ResizeMode = SharedTransitionScope.ResizeMode.RemeasureToBounds,
|
||||||
|
clipShape: Shape = MaterialTheme.shapes.largeIncreased,
|
||||||
|
renderInOverlayDuringTransition: Boolean = true,
|
||||||
|
): Modifier {
|
||||||
|
with(sharedTransitionScope) {
|
||||||
|
return this@sharedBoundsReveal
|
||||||
|
.sharedBounds(
|
||||||
|
sharedContentState = sharedContentState,
|
||||||
|
animatedVisibilityScope = animatedVisibilityScope,
|
||||||
|
boundsTransform = boundsTransform,
|
||||||
|
enter = enter,
|
||||||
|
exit = exit,
|
||||||
|
resizeMode = resizeMode,
|
||||||
|
clipInOverlayDuringTransition = OverlayClip(clipShape),
|
||||||
|
renderInOverlayDuringTransition = renderInOverlayDuringTransition,
|
||||||
|
)
|
||||||
|
.skipToLookaheadSize()
|
||||||
|
.skipToLookaheadPosition()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,10 +18,13 @@
|
|||||||
package org.nsh07.pomodoro.ui.statsScreen.screens
|
package org.nsh07.pomodoro.ui.statsScreen.screens
|
||||||
|
|
||||||
import android.graphics.Typeface
|
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.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
@@ -30,10 +33,11 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
|||||||
import androidx.compose.material3.FilledTonalIconButton
|
import androidx.compose.material3.FilledTonalIconButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButtonDefaults
|
import androidx.compose.material3.IconButtonDefaults
|
||||||
import androidx.compose.material3.LargeFlexibleTopAppBar
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -43,18 +47,21 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation3.ui.LocalNavAnimatedContentScope
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||||
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
||||||
import org.nsh07.pomodoro.R
|
import org.nsh07.pomodoro.R
|
||||||
import org.nsh07.pomodoro.ui.mergePaddingValues
|
import org.nsh07.pomodoro.ui.mergePaddingValues
|
||||||
import org.nsh07.pomodoro.ui.statsScreen.components.TimeColumnChart
|
import org.nsh07.pomodoro.ui.statsScreen.components.TimeColumnChart
|
||||||
|
import org.nsh07.pomodoro.ui.statsScreen.components.sharedBoundsReveal
|
||||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
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.millisecondsToHoursMinutes
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LastWeekScreen(
|
fun SharedTransitionScope.LastWeekScreen(
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
lastWeekAverageFocusTimes: List<Int>,
|
lastWeekAverageFocusTimes: List<Int>,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
@@ -66,7 +73,7 @@ fun LastWeekScreen(
|
|||||||
axisTypeface: Typeface,
|
axisTypeface: Typeface,
|
||||||
markerTypeface: Typeface
|
markerTypeface: Typeface
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||||
|
|
||||||
val rankList = remember(lastWeekAverageFocusTimes) {
|
val rankList = remember(lastWeekAverageFocusTimes) {
|
||||||
val sortedIndices =
|
val sortedIndices =
|
||||||
@@ -82,9 +89,17 @@ fun LastWeekScreen(
|
|||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
LargeFlexibleTopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
Text(stringResource(R.string.last_week), fontFamily = robotoFlexTopBar)
|
Text(
|
||||||
|
text = stringResource(R.string.last_week),
|
||||||
|
fontFamily = robotoFlexTopBar,
|
||||||
|
modifier = Modifier.sharedBounds(
|
||||||
|
sharedContentState = this@LastWeekScreen
|
||||||
|
.rememberSharedContentState("last week heading"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
subtitle = {
|
subtitle = {
|
||||||
Text(stringResource(R.string.stats))
|
Text(stringResource(R.string.stats))
|
||||||
@@ -100,18 +115,35 @@ fun LastWeekScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollBehavior = scrollBehavior
|
scrollBehavior = scrollBehavior,
|
||||||
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = colorScheme.surfaceBright,
|
||||||
|
scrolledContainerColor = colorScheme.surfaceBright
|
||||||
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
modifier = modifier
|
||||||
|
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
|
.sharedBoundsReveal(
|
||||||
|
sharedTransitionScope = this@LastWeekScreen,
|
||||||
|
sharedContentState = this@LastWeekScreen.rememberSharedContentState(
|
||||||
|
"last week card"
|
||||||
|
),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current,
|
||||||
|
clipShape = topListItemShape
|
||||||
|
)
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
val insets = mergePaddingValues(innerPadding, contentPadding)
|
val insets = mergePaddingValues(innerPadding, contentPadding)
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
contentPadding = insets,
|
contentPadding = insets,
|
||||||
modifier = Modifier.padding(horizontal = 16.dp)
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(colorScheme.surfaceBright)
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.Bottom,
|
verticalAlignment = Alignment.Bottom,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
@@ -123,12 +155,24 @@ fun LastWeekScreen(
|
|||||||
},
|
},
|
||||||
hoursMinutesFormat
|
hoursMinutesFormat
|
||||||
),
|
),
|
||||||
style = typography.displaySmall
|
style = typography.displaySmall,
|
||||||
|
modifier = Modifier
|
||||||
|
.sharedElement(
|
||||||
|
sharedContentState = this@LastWeekScreen
|
||||||
|
.rememberSharedContentState("last week average focus timer"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.focus_per_day_avg),
|
stringResource(R.string.focus_per_day_avg),
|
||||||
style = typography.titleSmall,
|
style = typography.titleSmall,
|
||||||
modifier = Modifier.padding(bottom = 5.2.dp)
|
modifier = Modifier
|
||||||
|
.padding(bottom = 5.2.dp)
|
||||||
|
.sharedElement(
|
||||||
|
sharedContentState = this@LastWeekScreen
|
||||||
|
.rememberSharedContentState("focus per day average (week)"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
@@ -141,7 +185,13 @@ fun LastWeekScreen(
|
|||||||
markerTypeface = markerTypeface,
|
markerTypeface = markerTypeface,
|
||||||
xValueFormatter = CartesianValueFormatter { context, x, _ ->
|
xValueFormatter = CartesianValueFormatter { context, x, _ ->
|
||||||
context.model.extraStore[lastWeekSummaryChartData.second][x.toInt()]
|
context.model.extraStore[lastWeekSummaryChartData.second][x.toInt()]
|
||||||
}
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.sharedElement(
|
||||||
|
sharedContentState = this@LastWeekScreen
|
||||||
|
.rememberSharedContentState("last week chart"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package org.nsh07.pomodoro.ui.statsScreen.screens
|
package org.nsh07.pomodoro.ui.statsScreen.screens
|
||||||
|
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
|
import androidx.compose.animation.SharedTransitionScope
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -26,6 +27,7 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
@@ -52,6 +54,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation3.ui.LocalNavAnimatedContentScope
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||||
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
||||||
@@ -62,6 +65,7 @@ import org.nsh07.pomodoro.ui.Screen
|
|||||||
import org.nsh07.pomodoro.ui.mergePaddingValues
|
import org.nsh07.pomodoro.ui.mergePaddingValues
|
||||||
import org.nsh07.pomodoro.ui.statsScreen.components.TimeColumnChart
|
import org.nsh07.pomodoro.ui.statsScreen.components.TimeColumnChart
|
||||||
import org.nsh07.pomodoro.ui.statsScreen.components.TimeLineChart
|
import org.nsh07.pomodoro.ui.statsScreen.components.TimeLineChart
|
||||||
|
import org.nsh07.pomodoro.ui.statsScreen.components.sharedBoundsReveal
|
||||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||||
import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors
|
import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors
|
||||||
import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors
|
import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors
|
||||||
@@ -72,7 +76,7 @@ import org.nsh07.pomodoro.utils.millisecondsToHoursMinutes
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun StatsMainScreen(
|
fun SharedTransitionScope.StatsMainScreen(
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
lastWeekSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
lastWeekSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
||||||
lastMonthSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
lastMonthSummaryChartData: Pair<CartesianChartModelProducer, ExtraStore.Key<List<String>>>,
|
||||||
@@ -90,7 +94,7 @@ fun StatsMainScreen(
|
|||||||
onNavigate: (Screen.Stats) -> Unit,
|
onNavigate: (Screen.Stats) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -102,7 +106,10 @@ fun StatsMainScreen(
|
|||||||
fontFamily = robotoFlexTopBar,
|
fontFamily = robotoFlexTopBar,
|
||||||
fontSize = 32.sp,
|
fontSize = 32.sp,
|
||||||
lineHeight = 32.sp
|
lineHeight = 32.sp
|
||||||
)
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
.padding(vertical = 14.dp)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
actions = if (BuildConfig.DEBUG) {
|
actions = if (BuildConfig.DEBUG) {
|
||||||
@@ -119,7 +126,8 @@ fun StatsMainScreen(
|
|||||||
subtitle = {},
|
subtitle = {},
|
||||||
titleHorizontalAlignment = Alignment.CenterHorizontally,
|
titleHorizontalAlignment = Alignment.CenterHorizontally,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
colors = topBarColors
|
colors = topBarColors,
|
||||||
|
windowInsets = WindowInsets()
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
@@ -212,6 +220,14 @@ fun StatsMainScreen(
|
|||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.sharedBoundsReveal(
|
||||||
|
sharedTransitionScope = this@StatsMainScreen,
|
||||||
|
sharedContentState = this@StatsMainScreen.rememberSharedContentState(
|
||||||
|
"last week card"
|
||||||
|
),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current,
|
||||||
|
clipShape = topListItemShape
|
||||||
|
)
|
||||||
.clip(topListItemShape)
|
.clip(topListItemShape)
|
||||||
.background(listItemColors.containerColor)
|
.background(listItemColors.containerColor)
|
||||||
.clickable { onNavigate(Screen.Stats.LastWeek) }
|
.clickable { onNavigate(Screen.Stats.LastWeek) }
|
||||||
@@ -223,7 +239,12 @@ fun StatsMainScreen(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.last_week),
|
stringResource(R.string.last_week),
|
||||||
style = typography.headlineSmall
|
style = typography.headlineSmall,
|
||||||
|
modifier = Modifier.sharedBounds(
|
||||||
|
sharedContentState = this@StatsMainScreen
|
||||||
|
.rememberSharedContentState("last week heading"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
@@ -237,12 +258,24 @@ fun StatsMainScreen(
|
|||||||
},
|
},
|
||||||
hoursMinutesFormat
|
hoursMinutesFormat
|
||||||
),
|
),
|
||||||
style = typography.displaySmall
|
style = typography.displaySmall,
|
||||||
|
modifier = Modifier
|
||||||
|
.sharedElement(
|
||||||
|
sharedContentState = this@StatsMainScreen
|
||||||
|
.rememberSharedContentState("last week average focus timer"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.focus_per_day_avg),
|
stringResource(R.string.focus_per_day_avg),
|
||||||
style = typography.titleSmall,
|
style = typography.titleSmall,
|
||||||
modifier = Modifier.padding(bottom = 5.2.dp)
|
modifier = Modifier
|
||||||
|
.padding(bottom = 5.2.dp)
|
||||||
|
.sharedElement(
|
||||||
|
sharedContentState = this@StatsMainScreen
|
||||||
|
.rememberSharedContentState("focus per day average (week)"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +288,13 @@ fun StatsMainScreen(
|
|||||||
markerTypeface = markerTypeface,
|
markerTypeface = markerTypeface,
|
||||||
xValueFormatter = CartesianValueFormatter { context, x, _ ->
|
xValueFormatter = CartesianValueFormatter { context, x, _ ->
|
||||||
context.model.extraStore[lastWeekSummaryChartData.second][x.toInt()]
|
context.model.extraStore[lastWeekSummaryChartData.second][x.toInt()]
|
||||||
}
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.sharedElement(
|
||||||
|
sharedContentState = this@StatsMainScreen
|
||||||
|
.rememberSharedContentState("last week chart"),
|
||||||
|
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user