From f6878cd4d9d2956e86dc9837bb3a2492638c13a1 Mon Sep 17 00:00:00 2001 From: zachseidner1 Date: Wed, 26 Mar 2025 20:58:00 -0400 Subject: [PATCH 1/6] Fix main view model scoping --- .../com/cornellappdev/score/MainActivity.kt | 3 - .../cornellappdev/score/nav/ScoreNavHost.kt | 43 +++++++ .../score/nav/ScoreNavigationBar.kt | 61 ++++++++++ .../score/nav/root/RootNavigation.kt | 106 ++++-------------- .../nav/root/RootNavigationRepository.kt | 2 +- .../score/nav/root/RootNavigationViewModel.kt | 4 +- 6 files changed, 130 insertions(+), 89 deletions(-) create mode 100644 app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt create mode 100644 app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt diff --git a/app/src/main/java/com/cornellappdev/score/MainActivity.kt b/app/src/main/java/com/cornellappdev/score/MainActivity.kt index a375d6d..549924b 100644 --- a/app/src/main/java/com/cornellappdev/score/MainActivity.kt +++ b/app/src/main/java/com/cornellappdev/score/MainActivity.kt @@ -1,17 +1,14 @@ package com.cornellappdev.score -import android.os.Build import android.os.Bundle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import com.cornellappdev.score.nav.root.RootNavigation import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class MainActivity : AppCompatActivity() { - @RequiresApi(Build.VERSION_CODES.O) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() diff --git a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt new file mode 100644 index 0000000..92d3277 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt @@ -0,0 +1,43 @@ +package com.cornellappdev.score.nav + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import com.cornellappdev.score.nav.root.ScoreScreens +import com.cornellappdev.score.nav.root.ScoreScreens.Home +import com.cornellappdev.score.screen.GameDetailsScreen +import com.cornellappdev.score.screen.HomeScreen +import com.cornellappdev.score.screen.PastGamesScreen + +@Composable +fun ScoreNavHost(navController: NavHostController) { + val mainScreenViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) + + NavHost( + navController = navController, + startDestination = Home + ) { + composable { + CompositionLocalProvider(LocalViewModelStoreOwner provides mainScreenViewModelStoreOwner) { + HomeScreen(navigateToGameDetails = { + navController.navigate(ScoreScreens.GameDetailsPage("")) + }) + } + } + composable { + CompositionLocalProvider(LocalViewModelStoreOwner provides mainScreenViewModelStoreOwner) { + PastGamesScreen(navigateToGameDetails = { + navController.navigate(ScoreScreens.GameDetailsPage("")) + }) + } + } + composable { + GameDetailsScreen("", onBackArrow = { + navController.navigateUp() + }) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt new file mode 100644 index 0000000..30f72ac --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavigationBar.kt @@ -0,0 +1,61 @@ +package com.cornellappdev.score.nav + +import androidx.compose.material3.Icon +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.navigation.NavBackStackEntry +import com.cornellappdev.score.nav.root.ScoreScreens +import com.cornellappdev.score.nav.root.tabs +import com.cornellappdev.score.nav.root.toScreen +import com.cornellappdev.score.theme.CrimsonPrimary +import com.cornellappdev.score.theme.GrayPrimary +import com.cornellappdev.score.theme.Style.bodyMedium +import com.cornellappdev.score.theme.White + +@Composable +fun ScoreNavigationBar( + navigateToScreen: (ScoreScreens) -> Unit, + navBackStackEntry: NavBackStackEntry?, + modifier: Modifier = Modifier, +) { + NavigationBar(modifier = modifier, containerColor = White) { + tabs.map { item -> + val isSelected = item.screen == navBackStackEntry?.toScreen() + + NavigationBarItem( + selected = isSelected, + onClick = { navigateToScreen(item.screen) }, + icon = { + Icon( + painter = painterResource(id = if (isSelected) item.selectedIcon else item.unselectedIcon), + contentDescription = null, + tint = Color.Unspecified + ) + }, + label = { + Text( + text = item.label, + style = bodyMedium, + color = if (isSelected) { + CrimsonPrimary + } else { + GrayPrimary + } + ) + } + ) + } + } +} + +@Preview +@Composable +private fun ScoreNavigationBarPreview() { + ScoreNavigationBar({}, null) +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt index 46181d0..2e33d07 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt @@ -3,34 +3,22 @@ package com.cornellappdev.score.nav.root import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Icon -import androidx.compose.material3.NavigationBar -import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavBackStackEntry -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute import com.cornellappdev.score.R -import com.cornellappdev.score.nav.root.ScoreRootScreens.Home.toScreen -import com.cornellappdev.score.screen.GameDetailsScreen -import com.cornellappdev.score.screen.HomeScreen -import com.cornellappdev.score.screen.PastGamesScreen -import com.cornellappdev.score.theme.CrimsonPrimary -import com.cornellappdev.score.theme.GrayPrimary -import com.cornellappdev.score.theme.Style.bodyMedium -import com.cornellappdev.score.theme.White +import com.cornellappdev.score.nav.ScoreNavHost +import com.cornellappdev.score.nav.ScoreNavigationBar +import com.cornellappdev.score.nav.root.ScoreScreens.GameDetailsPage +import com.cornellappdev.score.nav.root.ScoreScreens.Home +import com.cornellappdev.score.nav.root.ScoreScreens.ScoresScreen import kotlinx.serialization.Serializable -import java.time.LocalDate @Composable fun RootNavigation( @@ -46,88 +34,40 @@ fun RootNavigation( } } + Scaffold(modifier = Modifier.fillMaxSize(), bottomBar = { - NavigationBar(containerColor = White) { - tabs.map { item -> - val isSelected = item.screen == navBackStackEntry?.toScreen() - - NavigationBarItem( - selected = isSelected, - onClick = { navController.navigate(item.screen) }, - icon = { - Icon( - painter = painterResource(id = if (isSelected) item.selectedIcon else item.unselectedIcon), - contentDescription = null, - tint = Color.Unspecified - ) - }, - label = { - Text( - text = item.label, - style = bodyMedium, - color = if (isSelected) { - CrimsonPrimary - } else { - GrayPrimary - } - ) - } - ) - } - } + ScoreNavigationBar({ navController.navigate(it) }, navBackStackEntry) } ) { innerPadding -> Box(modifier = Modifier.padding(innerPadding)) { - NavHost( - navController = navController, - startDestination = ScoreRootScreens.Home - ) { - composable { - HomeScreen(navigateToGameDetails = { - navController.navigate(ScoreRootScreens.GameDetailsPage("")) - }) - } - - composable { - GameDetailsScreen("", onBackArrow = { - navController.navigateUp() - }) - - } - - composable { - PastGamesScreen(navigateToGameDetails = { - navController.navigate(ScoreRootScreens.GameDetailsPage("")) - }) - } - } + ScoreNavHost(navController) } } } @Serializable -sealed class ScoreRootScreens { +sealed class ScoreScreens { @Serializable - data object Home : ScoreRootScreens() + data object Home : ScoreScreens() @Serializable - data class GameDetailsPage(val gameId: String) : ScoreRootScreens() + data class GameDetailsPage(val gameId: String) : ScoreScreens() @Serializable - data object ScoresScreen : ScoreRootScreens() - - fun NavBackStackEntry.toScreen(): ScoreRootScreens? = - when (destination.route?.substringAfterLast(".")?.substringBefore("/")) { - "Home" -> toRoute() - "GameDetailsPage" -> toRoute() - "ScoresScreen" -> toRoute() - else -> throw IllegalArgumentException("Invalid screen") - } + data object ScoresScreen : ScoreScreens() } +fun NavBackStackEntry.toScreen(): ScoreScreens? = + when (destination.route?.substringAfterLast(".")?.substringBefore("/")) { + "Home" -> toRoute() + "GameDetailsPage" -> toRoute() + "ScoresScreen" -> toRoute() + else -> throw IllegalArgumentException("Invalid screen") + } + data class NavItem( - val screen: ScoreRootScreens, + val screen: ScoreScreens, val label: String, val unselectedIcon: Int, val selectedIcon: Int @@ -138,12 +78,12 @@ val tabs = listOf( label = "Schedule", unselectedIcon = R.drawable.ic_schedule, selectedIcon = R.drawable.ic_schedule_filled, - screen = ScoreRootScreens.Home, + screen = ScoreScreens.Home, ), NavItem( label = "Scores", unselectedIcon = R.drawable.ic_scores, selectedIcon = R.drawable.ic_scores_filled, - screen = ScoreRootScreens.ScoresScreen, + screen = ScoreScreens.ScoresScreen, ), ) \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationRepository.kt b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationRepository.kt index ad70d3e..9f0073e 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationRepository.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationRepository.kt @@ -5,4 +5,4 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class RootNavigationRepository @Inject constructor() : BaseNavigationRepository() +class RootNavigationRepository @Inject constructor() : BaseNavigationRepository() diff --git a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationViewModel.kt b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationViewModel.kt index d185c17..8d40cb6 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationViewModel.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigationViewModel.kt @@ -1,7 +1,7 @@ package com.cornellappdev.score.nav.root -import com.cornellappdev.score.viewmodel.BaseViewModel import com.cornellappdev.score.util.UIEvent +import com.cornellappdev.score.viewmodel.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -13,7 +13,7 @@ class RootNavigationViewModel @Inject constructor( ) { data class RootNavigationUiState( - val navigationEvent: UIEvent? = null, + val navigationEvent: UIEvent? = null, ) init { From 15ad1d7d59b300f87e4e35bd9fef2439bac5dab0 Mon Sep 17 00:00:00 2001 From: zachseidner1 Date: Wed, 26 Mar 2025 21:27:02 -0400 Subject: [PATCH 2/6] Bump material version in preparation for pull to refresh --- app/build.gradle.kts | 2 +- gradle/libs.versions.toml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5642ff1..0dfecfb 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -69,7 +69,7 @@ dependencies { implementation("androidx.activity:activity-compose") implementation("androidx.lifecycle:lifecycle-viewmodel-compose") implementation("androidx.navigation:navigation-compose:2.8.2") - implementation("androidx.compose.material3:material3:1.0.0") + implementation(libs.material3) implementation("com.google.dagger:hilt-android:2.51.1") kapt("com.google.dagger:hilt-android-compiler:2.51.1") implementation("androidx.hilt:hilt-navigation-compose:1.0.0") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cfdf911..f72f8bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,12 +7,13 @@ junit = "4.13.2" junitVersion = "1.1.5" espressoCore = "3.5.1" appcompat = "1.6.1" -material = "1.10.0" +material = "1.12.0" activity = "1.8.0" constraintlayout = "2.1.4" runtimeAndroid = "1.7.2" apollo = "4.1.1" media3CommonKtx = "1.5.1" +material3 = "1.3.1" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -22,6 +23,7 @@ androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "j androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } +material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } androidx-runtime-android = { group = "androidx.compose.runtime", name = "runtime-android", version.ref = "runtimeAndroid" } From c9d80c5bca537d743487775cb131192395a2c5b5 Mon Sep 17 00:00:00 2001 From: zachseidner1 Date: Wed, 26 Mar 2025 21:36:32 -0400 Subject: [PATCH 3/6] Add documentation --- app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt index 92d3277..be5b23e 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt @@ -14,6 +14,9 @@ import com.cornellappdev.score.screen.PastGamesScreen @Composable fun ScoreNavHost(navController: NavHostController) { + // This ViewModelStoreOwner is used to scope the past and home screen view models to the root + // screen instead of their individual tabs. This way the view models are not reconstructed + // everytime you switch tabs. val mainScreenViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) NavHost( From 9e9c79afacbef61c056e4bb991b2dad956f1757f Mon Sep 17 00:00:00 2001 From: zachseidner1 Date: Tue, 8 Apr 2025 13:50:18 -0400 Subject: [PATCH 4/6] Revert "Bump material version in preparation for pull to refresh" This reverts commit 15ad1d7d59b300f87e4e35bd9fef2439bac5dab0. --- app/build.gradle.kts | 2 +- gradle/libs.versions.toml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0dfecfb..5642ff1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -69,7 +69,7 @@ dependencies { implementation("androidx.activity:activity-compose") implementation("androidx.lifecycle:lifecycle-viewmodel-compose") implementation("androidx.navigation:navigation-compose:2.8.2") - implementation(libs.material3) + implementation("androidx.compose.material3:material3:1.0.0") implementation("com.google.dagger:hilt-android:2.51.1") kapt("com.google.dagger:hilt-android-compiler:2.51.1") implementation("androidx.hilt:hilt-navigation-compose:1.0.0") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f72f8bd..cfdf911 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,13 +7,12 @@ junit = "4.13.2" junitVersion = "1.1.5" espressoCore = "3.5.1" appcompat = "1.6.1" -material = "1.12.0" +material = "1.10.0" activity = "1.8.0" constraintlayout = "2.1.4" runtimeAndroid = "1.7.2" apollo = "4.1.1" media3CommonKtx = "1.5.1" -material3 = "1.3.1" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -23,7 +22,6 @@ androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "j androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } -material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } androidx-runtime-android = { group = "androidx.compose.runtime", name = "runtime-android", version.ref = "runtimeAndroid" } From 3a52895997bbf0ef9e606d7fb351de7392f637d4 Mon Sep 17 00:00:00 2001 From: zachseidner1 Date: Mon, 14 Apr 2025 22:26:57 -0400 Subject: [PATCH 5/6] Resolve merge conflicts --- .../cornellappdev/score/nav/root/RootNavigation.kt | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt index f73fc84..3475ef4 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt @@ -18,20 +18,12 @@ import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute import com.cornellappdev.score.R -import com.cornellappdev.score.nav.root.ScoreRootScreens.Home.toScreen -import com.cornellappdev.score.screen.GameDetailsScreen -import com.cornellappdev.score.screen.HomeScreen -import com.cornellappdev.score.screen.PastGamesScreen -import com.cornellappdev.score.theme.CrimsonPrimary -import com.cornellappdev.score.theme.GrayPrimary -import com.cornellappdev.score.theme.LocalInfiniteLoading -import com.cornellappdev.score.theme.Style.bodyMedium -import com.cornellappdev.score.theme.White import com.cornellappdev.score.nav.ScoreNavHost import com.cornellappdev.score.nav.ScoreNavigationBar import com.cornellappdev.score.nav.root.ScoreScreens.GameDetailsPage import com.cornellappdev.score.nav.root.ScoreScreens.Home import com.cornellappdev.score.nav.root.ScoreScreens.ScoresScreen +import com.cornellappdev.score.theme.LocalInfiniteLoading import kotlinx.serialization.Serializable @Composable @@ -66,7 +58,7 @@ fun RootNavigation( Scaffold(modifier = Modifier.fillMaxSize(), bottomBar = { - if (navBackStackEntry?.toScreen() is ScoreRootScreens.GameDetailsPage) { + if (navBackStackEntry?.toScreen() is GameDetailsPage) { return@Scaffold } ScoreNavigationBar({ navController.navigate(it) }, navBackStackEntry) @@ -75,7 +67,7 @@ fun RootNavigation( Box(modifier = Modifier.padding(innerPadding)) { CompositionLocalProvider(LocalInfiniteLoading provides animatedValue) { - ScoreNavHost(navController) + ScoreNavHost(navController) } } } From 78dea36f2132f0547b57377ff03f34088ad2e1a4 Mon Sep 17 00:00:00 2001 From: zachseidner1 Date: Mon, 14 Apr 2025 22:32:00 -0400 Subject: [PATCH 6/6] oopsies --- app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt index be5b23e..3d98427 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt @@ -38,7 +38,7 @@ fun ScoreNavHost(navController: NavHostController) { } } composable { - GameDetailsScreen("", onBackArrow = { + GameDetailsScreen(onBackArrow = { navController.navigateUp() }) }