Enable predictive back gestures, improve navigation animations

This commit is contained in:
Nishant Mishra
2025-07-04 18:06:41 +05:30
parent 8f3ee5359e
commit fd8b716ee9
6 changed files with 46 additions and 13 deletions

View File

@@ -40,6 +40,9 @@ android {
jvmTarget.set(JvmTarget.JVM_17) // Use the enum for target JVM version jvmTarget.set(JvmTarget.JVM_17) // Use the enum for target JVM version
} }
} }
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}
buildFeatures { buildFeatures {
compose = true compose = true
} }

View File

@@ -6,12 +6,14 @@
android:name=".TomatoApplication" android:name=".TomatoApplication"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="true"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Tomato"> android:theme="@style/Theme.Tomato"
tools:targetApi="36">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@@ -1,12 +1,17 @@
package org.nsh07.pomodoro.ui package org.nsh07.pomodoro.ui
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme.motionScheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.ShortNavigationBar import androidx.compose.material3.ShortNavigationBar
import androidx.compose.material3.ShortNavigationBarItem import androidx.compose.material3.ShortNavigationBarItem
@@ -19,6 +24,8 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -48,6 +55,10 @@ fun AppScreen(
val progress by rememberUpdatedState((uiState.totalTime.toFloat() - remainingTime) / uiState.totalTime) val progress by rememberUpdatedState((uiState.totalTime.toFloat() - remainingTime) / uiState.totalTime)
var showBrandTitle by remember { mutableStateOf(true) } var showBrandTitle by remember { mutableStateOf(true) }
val layoutDirection = LocalLayoutDirection.current
val haptic = LocalHapticFeedback.current
val motionScheme = motionScheme
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
delay(1500) delay(1500)
@@ -55,7 +66,9 @@ fun AppScreen(
} }
} }
val layoutDirection = LocalLayoutDirection.current LaunchedEffect(uiState.timerMode) {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}
val backStack = rememberNavBackStack<Screen>(Screen.Timer) val backStack = rememberNavBackStack<Screen>(Screen.Timer)
@@ -75,7 +88,7 @@ fun AppScreen(
{ if (backStack.size > 1) backStack.removeAt(1) } { if (backStack.size > 1) backStack.removeAt(1) }
}, },
icon = { icon = {
Crossfade (selected) { selected -> Crossfade(selected) { selected ->
if (selected) Icon(painterResource(it.selectedIcon), null) if (selected) Icon(painterResource(it.selectedIcon), null)
else Icon(painterResource(it.unselectedIcon), null) else Icon(painterResource(it.unselectedIcon), null)
} }
@@ -89,6 +102,25 @@ fun AppScreen(
NavDisplay( NavDisplay(
backStack = backStack, backStack = backStack,
onBack = { backStack.removeLastOrNull() }, onBack = { backStack.removeLastOrNull() },
transitionSpec = {
ContentTransform(
fadeIn(motionScheme.defaultEffectsSpec()),
fadeOut(motionScheme.defaultEffectsSpec())
)
},
popTransitionSpec = {
ContentTransform(
fadeIn(motionScheme.defaultEffectsSpec()),
fadeOut(motionScheme.defaultEffectsSpec())
)
},
predictivePopTransitionSpec = {
ContentTransform(
fadeIn(motionScheme.defaultEffectsSpec()),
fadeOut(motionScheme.defaultEffectsSpec()) +
scaleOut(targetScale = 0.7f),
)
},
entryProvider = entryProvider { entryProvider = entryProvider {
entry<Screen.Timer> { entry<Screen.Timer> {
TimerScreen( TimerScreen(

View File

@@ -1,5 +1,6 @@
package org.nsh07.pomodoro.ui.settingsScreen package org.nsh07.pomodoro.ui.settingsScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@@ -7,6 +8,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.LoadingIndicator
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
@@ -34,7 +36,7 @@ fun SettingsScreen(modifier: Modifier = Modifier) {
subtitle = {}, subtitle = {},
titleHorizontalAlignment = Alignment.CenterHorizontally titleHorizontalAlignment = Alignment.CenterHorizontally
) )
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) { Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize().background(colorScheme.surface)) {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
LoadingIndicator() LoadingIndicator()
Text("Coming Soon", style = typography.headlineSmall, fontFamily = robotoFlexTitle) Text("Coming Soon", style = typography.headlineSmall, fontFamily = robotoFlexTitle)

View File

@@ -1,5 +1,6 @@
package org.nsh07.pomodoro.ui.statsScreen package org.nsh07.pomodoro.ui.statsScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@@ -7,6 +8,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.LoadingIndicator
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
@@ -34,7 +36,7 @@ fun StatsScreen(modifier: Modifier = Modifier) {
subtitle = {}, subtitle = {},
titleHorizontalAlignment = Alignment.CenterHorizontally titleHorizontalAlignment = Alignment.CenterHorizontally
) )
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) { Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize().background(colorScheme.surface)) {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
LoadingIndicator() LoadingIndicator()
Text("Coming Soon", style = typography.headlineSmall, fontFamily = robotoFlexTitle) Text("Coming Soon", style = typography.headlineSmall, fontFamily = robotoFlexTitle)

View File

@@ -34,16 +34,13 @@ import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@@ -71,7 +68,6 @@ fun TimerScreen(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val motionScheme = motionScheme val motionScheme = motionScheme
val haptic = LocalHapticFeedback.current
val color by animateColorAsState( val color by animateColorAsState(
if (uiState.timerMode == TimerMode.FOCUS) colorScheme.primary if (uiState.timerMode == TimerMode.FOCUS) colorScheme.primary
@@ -89,10 +85,6 @@ fun TimerScreen(
animationSpec = motionScheme.slowEffectsSpec() animationSpec = motionScheme.slowEffectsSpec()
) )
LaunchedEffect(uiState.timerMode) {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}
Column(modifier = modifier) { Column(modifier = modifier) {
TopAppBar( TopAppBar(
title = { title = {