From 01c75077c7ab575a989adc3142a867ce8235cf03 Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Mon, 20 Oct 2025 11:53:44 +0530 Subject: [PATCH] feat(ui): implement a simple click mechanism to switch to AOD --- .../java/org/nsh07/pomodoro/MainActivity.kt | 2 +- .../java/org/nsh07/pomodoro/ui/AppScreen.kt | 271 ++++++++++-------- 2 files changed, 151 insertions(+), 122 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt b/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt index baf7924..9a40b41 100644 --- a/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt +++ b/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt @@ -51,7 +51,7 @@ class MainActivity : ComponentActivity() { appContainer.appTimerRepository.colorScheme = colorScheme } - AppScreen(timerViewModel = timerViewModel) + AppScreen(timerViewModel = timerViewModel, isAODEnabled = true) } } } diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt index 59390fd..4bbdc6e 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt @@ -8,13 +8,17 @@ package org.nsh07.pomodoro.ui import android.content.Intent +import androidx.compose.animation.AnimatedContent import androidx.compose.animation.ContentTransform import androidx.compose.animation.Crossfade import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleOut +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @@ -25,13 +29,17 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.ShortNavigationBar import androidx.compose.material3.ShortNavigationBarArrangement import androidx.compose.material3.ShortNavigationBarItem +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.painterResource @@ -55,7 +63,8 @@ import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel @Composable fun AppScreen( modifier: Modifier = Modifier, - timerViewModel: TimerViewModel = viewModel(factory = TimerViewModel.Factory) + timerViewModel: TimerViewModel = viewModel(factory = TimerViewModel.Factory), + isAODEnabled: Boolean ) { val context = LocalContext.current @@ -69,6 +78,7 @@ fun AppScreen( val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass val backStack = rememberNavBackStack(Screen.Timer) + var showAOD by remember { mutableStateOf(false) } if (uiState.alarmRinging) AlarmDialog { @@ -78,128 +88,147 @@ fun AppScreen( } } - Scaffold( - bottomBar = { - val wide = remember { - windowSizeClass.isWidthAtLeastBreakpoint( - WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND + AnimatedContent( + showAOD, + transitionSpec = { fadeIn().togetherWith(fadeOut()) } + ) { aod -> + if (!aod) { + Scaffold( + bottomBar = { + val wide = remember { + windowSizeClass.isWidthAtLeastBreakpoint( + WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND + ) + } + ShortNavigationBar( + arrangement = + if (wide) ShortNavigationBarArrangement.Centered + else ShortNavigationBarArrangement.EqualWeight + ) { + screens.forEach { + val selected = backStack.last() == it.route + ShortNavigationBarItem( + selected = selected, + onClick = if (it.route != Screen.Timer) { // Ensure the backstack does not accumulate screens + { + if (backStack.size < 2) backStack.add(it.route) + else backStack[1] = it.route + } + } else { + { if (backStack.size > 1) backStack.removeAt(1) } + }, + icon = { + Crossfade(selected) { selected -> + if (selected) Icon(painterResource(it.selectedIcon), null) + else Icon(painterResource(it.unselectedIcon), null) + } + }, + iconPosition = + if (wide) NavigationItemIconPosition.Start + else NavigationItemIconPosition.Top, + label = { Text(stringResource(it.label)) } + ) + } + } + }, + modifier = Modifier + .then( + if (isAODEnabled) Modifier.clickable { showAOD = !showAOD } + else Modifier + ) + ) { contentPadding -> + NavDisplay( + backStack = backStack, + 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 { + entry { + TimerScreen( + timerState = uiState, + progress = { progress }, + onAction = { action -> + when (action) { + TimerAction.ResetTimer -> + Intent(context, TimerService::class.java).also { + it.action = TimerService.Actions.RESET.toString() + context.startService(it) + } + + is TimerAction.SkipTimer -> + Intent(context, TimerService::class.java).also { + it.action = TimerService.Actions.SKIP.toString() + context.startService(it) + } + + TimerAction.StopAlarm -> + Intent(context, TimerService::class.java).also { + it.action = + TimerService.Actions.STOP_ALARM.toString() + context.startService(it) + } + + TimerAction.ToggleTimer -> + Intent(context, TimerService::class.java).also { + it.action = TimerService.Actions.TOGGLE.toString() + context.startService(it) + } + } + }, + modifier = modifier.padding( + start = contentPadding.calculateStartPadding(layoutDirection), + end = contentPadding.calculateEndPadding(layoutDirection), + bottom = contentPadding.calculateBottomPadding() + ) + ) + } + + entry { + SettingsScreenRoot( + modifier = modifier.padding( + start = contentPadding.calculateStartPadding(layoutDirection), + end = contentPadding.calculateEndPadding(layoutDirection), + bottom = contentPadding.calculateBottomPadding() + ) + ) + } + + entry { + StatsScreenRoot( + contentPadding = contentPadding, + modifier = modifier.padding( + start = contentPadding.calculateStartPadding(layoutDirection), + end = contentPadding.calculateEndPadding(layoutDirection), + bottom = contentPadding.calculateBottomPadding() + ) + ) + } + } ) } - ShortNavigationBar( - arrangement = - if (wide) ShortNavigationBarArrangement.Centered - else ShortNavigationBarArrangement.EqualWeight - ) { - screens.forEach { - val selected = backStack.last() == it.route - ShortNavigationBarItem( - selected = selected, - onClick = if (it.route != Screen.Timer) { // Ensure the backstack does not accumulate screens - { - if (backStack.size < 2) backStack.add(it.route) - else backStack[1] = it.route - } - } else { - { if (backStack.size > 1) backStack.removeAt(1) } - }, - icon = { - Crossfade(selected) { selected -> - if (selected) Icon(painterResource(it.selectedIcon), null) - else Icon(painterResource(it.unselectedIcon), null) - } - }, - iconPosition = - if (wide) NavigationItemIconPosition.Start - else NavigationItemIconPosition.Top, - label = { Text(stringResource(it.label)) } - ) - } - } + } else { + Surface( + color = Color.Black, + modifier = Modifier + .fillMaxSize() + .clickable { showAOD = !showAOD }) {} } - ) { contentPadding -> - NavDisplay( - backStack = backStack, - 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 { - entry { - TimerScreen( - timerState = uiState, - progress = { progress }, - onAction = { action -> - when (action) { - TimerAction.ResetTimer -> - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.RESET.toString() - context.startService(it) - } - - is TimerAction.SkipTimer -> - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.SKIP.toString() - context.startService(it) - } - - TimerAction.StopAlarm -> - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.STOP_ALARM.toString() - context.startService(it) - } - - TimerAction.ToggleTimer -> - Intent(context, TimerService::class.java).also { - it.action = TimerService.Actions.TOGGLE.toString() - context.startService(it) - } - } - }, - modifier = modifier.padding( - start = contentPadding.calculateStartPadding(layoutDirection), - end = contentPadding.calculateEndPadding(layoutDirection), - bottom = contentPadding.calculateBottomPadding() - ) - ) - } - - entry { - SettingsScreenRoot( - modifier = modifier.padding( - start = contentPadding.calculateStartPadding(layoutDirection), - end = contentPadding.calculateEndPadding(layoutDirection), - bottom = contentPadding.calculateBottomPadding() - ) - ) - } - - entry { - StatsScreenRoot( - contentPadding = contentPadding, - modifier = modifier.padding( - start = contentPadding.calculateStartPadding(layoutDirection), - end = contentPadding.calculateEndPadding(layoutDirection), - bottom = contentPadding.calculateBottomPadding() - ) - ) - } - } - ) } } \ No newline at end of file