diff --git a/.gitignore b/.gitignore index 138b236..843be65 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ .externalNativeBuild .cxx local.properties +gradle.properties *.patch diff --git a/Reef/src/main/java/dev/pranav/reef/MainActivity.kt b/Reef/src/main/java/dev/pranav/reef/MainActivity.kt index 1c27085..5f451fc 100644 --- a/Reef/src/main/java/dev/pranav/reef/MainActivity.kt +++ b/Reef/src/main/java/dev/pranav/reef/MainActivity.kt @@ -13,6 +13,8 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.* +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -127,7 +129,7 @@ class MainActivity: ComponentActivity() { currentDestination?.hasRoute() == true -> 1 currentDestination?.hasRoute() == true -> 2 currentDestination?.hasRoute() == true -> 3 - else -> 0 + else -> -1 } } @@ -210,22 +212,25 @@ class MainActivity: ComponentActivity() { restoreState = true } when (index) { - 0 -> if (selectedNavIndex != 0) navController.navigate( - Screen.Home, - options - ) + 0 -> navController.navigate(Screen.Home) { + popUpTo(navController.graph.startDestinationId) { + saveState = true + } + launchSingleTop = true + restoreState = false + } - 1 -> if (selectedNavIndex != 1) navController.navigate( + 1 -> navController.navigate( Screen.Usage, options ) - 2 -> if (selectedNavIndex != 2) navController.navigate( + 2 -> navController.navigate( Screen.Timer, options ) - 3 -> if (selectedNavIndex != 3) navController.navigate( + 3 -> navController.navigate( Screen.Settings, options ) @@ -249,31 +254,43 @@ class MainActivity: ComponentActivity() { ) ), enterTransition = { - fadeIn(animationSpec = tween(250)) + - slideInHorizontally( - initialOffsetX = { it / 8 }, - animationSpec = tween(250) + fadeIn(animationSpec = tween(300)) + + slideIntoContainer( + towards = AnimatedContentTransitionScope.SlideDirection.Start, + animationSpec = spring( + dampingRatio = 0.8f, + stiffness = 300f + ) ) }, exitTransition = { - fadeOut(animationSpec = tween(250)) + - slideOutHorizontally( - targetOffsetX = { -it / 8 }, - animationSpec = tween(250) + fadeOut(animationSpec = tween(300)) + + slideOutOfContainer( + towards = AnimatedContentTransitionScope.SlideDirection.Start, + animationSpec = spring( + dampingRatio = 0.8f, + stiffness = 300f + ) ) }, popEnterTransition = { - fadeIn(animationSpec = tween(250)) + - slideInHorizontally( - initialOffsetX = { -it / 8 }, - animationSpec = tween(250) + fadeIn(animationSpec = tween(300)) + + slideIntoContainer( + towards = AnimatedContentTransitionScope.SlideDirection.End, + animationSpec = spring( + dampingRatio = 0.8f, + stiffness = 300f + ) ) }, popExitTransition = { - fadeOut(animationSpec = tween(250)) + - slideOutHorizontally( - targetOffsetX = { it / 8 }, - animationSpec = tween(250) + fadeOut(animationSpec = tween(300)) + + slideOutOfContainer( + towards = AnimatedContentTransitionScope.SlideDirection.End, + animationSpec = spring( + dampingRatio = 0.8f, + stiffness = 300f + ) ) } ) { diff --git a/Reef/src/main/java/dev/pranav/reef/MainScreen.kt b/Reef/src/main/java/dev/pranav/reef/MainScreen.kt index 5349903..5867230 100644 --- a/Reef/src/main/java/dev/pranav/reef/MainScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/MainScreen.kt @@ -120,12 +120,11 @@ fun HomeContent( Column( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .padding(paddingValues) + .verticalScroll(rememberScrollState()) .padding(horizontal = 16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Spacer(Modifier.height(8.dp)) FocusModeCard( diff --git a/Reef/src/main/java/dev/pranav/reef/PermissionsCheckActivity.kt b/Reef/src/main/java/dev/pranav/reef/PermissionsCheckActivity.kt index 71c442d..e263afe 100644 --- a/Reef/src/main/java/dev/pranav/reef/PermissionsCheckActivity.kt +++ b/Reef/src/main/java/dev/pranav/reef/PermissionsCheckActivity.kt @@ -77,7 +77,7 @@ fun PermissionsScreen(onBackClick: () -> Unit) { Scaffold( topBar = { - TopAppBar( + MediumTopAppBar( title = { Text(stringResource(R.string.required_permissions)) }, navigationIcon = { IconButton(onClick = onBackClick) { diff --git a/Reef/src/main/java/dev/pranav/reef/screens/CreateRoutineScreen.kt b/Reef/src/main/java/dev/pranav/reef/screens/CreateRoutineScreen.kt index 75d82f0..e2d68b8 100644 --- a/Reef/src/main/java/dev/pranav/reef/screens/CreateRoutineScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/screens/CreateRoutineScreen.kt @@ -92,7 +92,7 @@ fun CreateRoutineScreen( contentWindowInsets = WindowInsets(0), snackbarHost = { SnackbarHost(snackbarHostState) }, topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text( if (currentRoutine != null) stringResource(R.string.edit_routine) diff --git a/Reef/src/main/java/dev/pranav/reef/screens/DailyLimitScreen.kt b/Reef/src/main/java/dev/pranav/reef/screens/DailyLimitScreen.kt index 8f5206f..515ea86 100644 --- a/Reef/src/main/java/dev/pranav/reef/screens/DailyLimitScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/screens/DailyLimitScreen.kt @@ -55,7 +55,7 @@ fun DailyLimitScreen( contentWindowInsets = WindowInsets(0), containerColor = MaterialTheme.colorScheme.surface, topBar = { - TopAppBar( + MediumTopAppBar( title = { Text(stringResource(R.string.daily_usage_limit)) }, navigationIcon = { IconButton(onClick = onBackPressed) { diff --git a/Reef/src/main/java/dev/pranav/reef/screens/NotificationSettingsScreen.kt b/Reef/src/main/java/dev/pranav/reef/screens/NotificationSettingsScreen.kt index c33c773..e4008ee 100644 --- a/Reef/src/main/java/dev/pranav/reef/screens/NotificationSettingsScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/screens/NotificationSettingsScreen.kt @@ -40,7 +40,7 @@ fun NotificationSettingsContent( Scaffold( topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text(stringResource(R.string.notifications_settings_title)) }, navigationIcon = { IconButton(onClick = onBackPressed) { diff --git a/Reef/src/main/java/dev/pranav/reef/screens/PomodoroSettingsScreen.kt b/Reef/src/main/java/dev/pranav/reef/screens/PomodoroSettingsScreen.kt index c21acf1..de2f7dc 100644 --- a/Reef/src/main/java/dev/pranav/reef/screens/PomodoroSettingsScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/screens/PomodoroSettingsScreen.kt @@ -122,7 +122,7 @@ fun PomodoroSettingsContent( Scaffold( topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text(stringResource(R.string.pomodoro_settings_title)) }, navigationIcon = { IconButton(onClick = onBackPressed) { diff --git a/Reef/src/main/java/dev/pranav/reef/screens/RoutinesScreen.kt b/Reef/src/main/java/dev/pranav/reef/screens/RoutinesScreen.kt index 956bdd6..8f10781 100644 --- a/Reef/src/main/java/dev/pranav/reef/screens/RoutinesScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/screens/RoutinesScreen.kt @@ -66,7 +66,7 @@ fun RoutinesScreen( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), contentWindowInsets = WindowInsets(0), topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text(stringResource(R.string.routines)) }, colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), scrollBehavior = scrollBehavior, @@ -90,10 +90,13 @@ fun RoutinesScreen( snackbarHost = { SnackbarHost(snackbarHostState) } ) { paddingValues -> LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(paddingValues), - contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues( + start = 16.dp, + end = 16.dp, + top = paddingValues.calculateTopPadding() + 8.dp, + bottom = paddingValues.calculateBottomPadding() + 8.dp + ), verticalArrangement = Arrangement.spacedBy(16.dp) ) { item { diff --git a/Reef/src/main/java/dev/pranav/reef/screens/ScreenWrappers.kt b/Reef/src/main/java/dev/pranav/reef/screens/ScreenWrappers.kt index dbbd75b..951b6e8 100644 --- a/Reef/src/main/java/dev/pranav/reef/screens/ScreenWrappers.kt +++ b/Reef/src/main/java/dev/pranav/reef/screens/ScreenWrappers.kt @@ -55,7 +55,7 @@ fun UsageScreenWrapper( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), contentWindowInsets = WindowInsets(0), topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text(stringResource(R.string.app_usage)) }, colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), scrollBehavior = scrollBehavior diff --git a/Reef/src/main/java/dev/pranav/reef/screens/SettingsScreen.kt b/Reef/src/main/java/dev/pranav/reef/screens/SettingsScreen.kt index 93d10e8..854988a 100644 --- a/Reef/src/main/java/dev/pranav/reef/screens/SettingsScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/screens/SettingsScreen.kt @@ -20,11 +20,6 @@ fun SettingsContent( val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) - LaunchedEffect(currentScreen) { - scrollBehavior.state.heightOffset = 0f - scrollBehavior.state.contentOffset = 0f - } - Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), contentWindowInsets = WindowInsets(0), @@ -34,7 +29,7 @@ fun SettingsContent( enter = fadeIn(), exit = fadeOut() ) { - LargeTopAppBar( + MediumTopAppBar( title = { Text(stringResource(R.string.settings)) }, colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), scrollBehavior = scrollBehavior diff --git a/Reef/src/main/java/dev/pranav/reef/timer/TimerScreen.kt b/Reef/src/main/java/dev/pranav/reef/timer/TimerScreen.kt index a241508..a8cde2b 100644 --- a/Reef/src/main/java/dev/pranav/reef/timer/TimerScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/timer/TimerScreen.kt @@ -1,6 +1,7 @@ package dev.pranav.reef.timer import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -63,47 +64,39 @@ fun TimerContent( val showRunningView = isTimerRunning || isPaused var selectedMode by remember { mutableIntStateOf(0) } - val setupScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) - val runningScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) - - val scrollBehavior = if (showRunningView) runningScrollBehavior else setupScrollBehavior + val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), contentWindowInsets = WindowInsets(0), topBar = { - - LargeTopAppBar( - title = { - Column( - verticalArrangement = Arrangement.spacedBy(16.dp), - ) { - Text( - stringResource(R.string.focus_mode_title) - ) - - if (!showRunningView) { - FocusModeGroup( - selectedMode = selectedMode, - onSelectionChange = { selectedMode = it }) - - Spacer(modifier = Modifier.height(8.dp)) + Column(modifier = Modifier.animateContentSize()) { + MediumTopAppBar( + title = { + Text(stringResource(R.string.focus_mode_title)) + }, + actions = { + IconButton(onClick = { navController.navigate(Screen.FocusStats) }) { + Icon( + Icons.Outlined.BarChart, + contentDescription = "Focus Stats" + ) } - } - }, - actions = { - IconButton(onClick = { navController.navigate(Screen.FocusStats) }) { - Icon( - Icons.Outlined.BarChart, - contentDescription = "Focus Stats" - ) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.Transparent - ), - scrollBehavior = scrollBehavior - ) + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Transparent + ), + scrollBehavior = scrollBehavior + ) + + if (!showRunningView) { + FocusModeGroup( + selectedMode = selectedMode, + onSelectionChange = { selectedMode = it } + ) + Spacer(modifier = Modifier.height(8.dp)) + } + } } ) { paddingValues -> Box( @@ -130,15 +123,13 @@ fun TimerContent( .verticalScroll(rememberScrollState()) .padding(horizontal = 24.dp) ) { - Column(modifier = Modifier.fillMaxWidth()) { - Spacer(modifier = Modifier.height(24.dp)) - - Box(modifier = Modifier.fillMaxWidth()) { - if (selectedMode == 0) { - SimpleFocusSetup(onStartTimer) - } else { - PomodoroFocusSetup(onStartTimer) - } + Spacer(modifier = Modifier.height(16.dp)) + + Box(modifier = Modifier.fillMaxWidth()) { + if (selectedMode == 0) { + SimpleFocusSetup(onStartTimer) + } else { + PomodoroFocusSetup(onStartTimer) } } } diff --git a/Reef/src/main/java/dev/pranav/reef/ui/about/AboutScreen.kt b/Reef/src/main/java/dev/pranav/reef/ui/about/AboutScreen.kt index 44514a3..dbabb59 100644 --- a/Reef/src/main/java/dev/pranav/reef/ui/about/AboutScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/ui/about/AboutScreen.kt @@ -44,7 +44,7 @@ fun AboutScreen( Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text( stringResource(R.string.about), diff --git a/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusSessionDetailScreen.kt b/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusSessionDetailScreen.kt index 6c3dfe0..2710f2a 100644 --- a/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusSessionDetailScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusSessionDetailScreen.kt @@ -66,7 +66,7 @@ fun FocusSessionDetailScreen(sessionId: String, onBackPressed: () -> Unit) { Scaffold( contentWindowInsets = WindowInsets(0), topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text( "Session Detail", diff --git a/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusStatsScreen.kt b/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusStatsScreen.kt index d47f48c..70120be 100644 --- a/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusStatsScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/ui/focusstats/FocusStatsScreen.kt @@ -137,7 +137,7 @@ fun FocusStatsScreen( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), contentWindowInsets = WindowInsets(0), topBar = { - LargeTopAppBar( + MediumTopAppBar( title = { Text( "Focus Stats", diff --git a/Reef/src/main/java/dev/pranav/reef/ui/whitelist/WhitelistScreen.kt b/Reef/src/main/java/dev/pranav/reef/ui/whitelist/WhitelistScreen.kt index d16a3dd..f771fa0 100644 --- a/Reef/src/main/java/dev/pranav/reef/ui/whitelist/WhitelistScreen.kt +++ b/Reef/src/main/java/dev/pranav/reef/ui/whitelist/WhitelistScreen.kt @@ -60,59 +60,58 @@ fun WhitelistScreen( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), contentWindowInsets = WindowInsets(0), topBar = { - LargeTopAppBar( - title = { - Column( - modifier = Modifier.padding(bottom = 12.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { + Column { + MediumTopAppBar( + title = { Text(stringResource(R.string.whitelist_apps_title)) - - OutlinedTextField( - value = searchQuery, - onValueChange = onSearchQueryChange, - modifier = Modifier.fillMaxWidth(), - placeholder = { - Text( - "Search apps...", - style = MaterialTheme.typography.bodyLarge - ) - }, - leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) }, - trailingIcon = { - if (searchQuery.isNotEmpty()) { - IconButton(onClick = { onSearchQueryChange("") }) { - Icon( - Icons.Default.Close, - contentDescription = "Clear search" - ) - } - } - }, - shape = RoundedCornerShape(28.dp), - singleLine = true, - textStyle = MaterialTheme.typography.bodyLarge, - colors = OutlinedTextFieldDefaults.colors( - focusedContainerColor = Color.Transparent, - unfocusedContainerColor = Color.Transparent, + }, + navigationIcon = { + IconButton(onClick = { onBackPress() }) { + Icon( + Icons.AutoMirrored.Rounded.ArrowBack, + contentDescription = stringResource(R.string.back) ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Transparent, + scrolledContainerColor = MaterialTheme.colorScheme.surface + ), + scrollBehavior = scrollBehavior + ) + + OutlinedTextField( + value = searchQuery, + onValueChange = onSearchQueryChange, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + placeholder = { + Text( + "Search apps...", + style = MaterialTheme.typography.bodyLarge ) - } - }, - navigationIcon = { - IconButton(onClick = { onBackPress() }) { - Icon( - Icons.AutoMirrored.Rounded.ArrowBack, - contentDescription = stringResource(R.string.back) - ) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = Color.Transparent, - scrolledContainerColor = MaterialTheme.colorScheme.surface - ), - scrollBehavior = scrollBehavior - ) + }, + leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) }, + trailingIcon = { + if (searchQuery.isNotEmpty()) { + IconButton(onClick = { onSearchQueryChange("") }) { + Icon( + Icons.Default.Close, + contentDescription = "Clear search" + ) + } + } + }, + shape = RoundedCornerShape(28.dp), + singleLine = true, + textStyle = MaterialTheme.typography.bodyLarge, + colors = OutlinedTextFieldDefaults.colors( + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + ) + ) + } } ) { paddingValues -> Box( diff --git a/gradle.properties b/gradle.properties index e297c4d..1fbc403 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,11 +6,10 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx3072m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. For more details, visit # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects -# org.gradle.parallel=true # AndroidX package structure to make it clearer which packages are bundled with the # Android operating system, and which are packaged with your app's APK # https://developer.android.com/topic/libraries/support-library/androidx-rn @@ -21,7 +20,6 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -org.gradle.workers.max=4 org.gradle.parallel=true org.gradle.caching=true org.gradle.configureondemand=true