Skip to content

Commit

Permalink
Migrate to typesafe navigation routes where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
arkon committed May 18, 2024
1 parent 6b3a932 commit f1211b1
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 58 deletions.
2 changes: 1 addition & 1 deletion app/src/main/kotlin/com/livetl/android/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.navigation.NavHostController
import com.livetl.android.ui.navigation.mainNavHost
import com.livetl.android.ui.navigation.Route
import com.livetl.android.ui.navigation.mainNavHost
import com.livetl.android.ui.navigation.navigateToPlayer
import com.livetl.android.ui.theme.LiveTLTheme
import com.livetl.android.util.AppPreferences
Expand Down
61 changes: 22 additions & 39 deletions app/src/main/kotlin/com/livetl/android/ui/navigation/MainNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package com.livetl.android.ui.navigation

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.navigation.ModalBottomSheetLayout
import androidx.compose.material.navigation.bottomSheet
import androidx.compose.material.navigation.rememberBottomSheetNavigator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand All @@ -12,26 +15,20 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import androidx.navigation.plusAssign
import com.google.accompanist.navigation.material.ModalBottomSheetLayout
import com.google.accompanist.navigation.material.bottomSheet
import com.google.accompanist.navigation.material.rememberBottomSheetNavigator
import androidx.navigation.toRoute
import com.livetl.android.ui.screen.about.AboutScreen
import com.livetl.android.ui.screen.about.LicensesScreen
import com.livetl.android.ui.screen.home.HomeScreen
import com.livetl.android.ui.screen.home.HomeViewModel
import com.livetl.android.ui.screen.home.composable.StreamInfo
import com.livetl.android.ui.screen.home.composable.StreamInfoViewModel
import com.livetl.android.ui.screen.home.settings.SettingsScreen
import com.livetl.android.ui.screen.home.settings.SettingsViewModel
import com.livetl.android.ui.screen.player.PlayerScreen
import com.livetl.android.ui.screen.player.PlayerViewModel
import com.livetl.android.ui.screen.welcome.WelcomeScreen
import com.livetl.android.ui.screen.welcome.WelcomeViewModel

fun NavHostController.navigateToPlayer(urlOrId: String) {
navigate("${Route.Player.id}?urlOrId=$urlOrId") {
navigate(Route.Player(urlOrId)) {
launchSingleTop = true
popUpTo(Route.Home.id) {}
popUpTo(Route.Home) {}
}
}

Expand All @@ -56,72 +53,58 @@ fun mainNavHost(
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
) {
NavHost(navController, startDestination = startRoute.id) {
composable(Route.Home.id) {
val homeViewModel = hiltViewModel<HomeViewModel>()

NavHost(navController, startDestination = startRoute) {
composable<Route.Home> {
HomeScreen(
navigateToStreamInfo = { navController.navigate("${Route.StreamInfo.id}?urlOrId=$it") },
navigateToStreamInfo = { navController.navigate("${Route.StreamInfo}?urlOrId=$it") },
navigateToPlayer = { navController.navigateToPlayer(it) },
navigateToSettings = { navController.navigate(Route.Settings.id) },
navigateToAbout = { navController.navigate(Route.About.id) },
viewModel = homeViewModel,
navigateToSettings = { navController.navigate(Route.Settings) },
navigateToAbout = { navController.navigate(Route.About) },
)
}

// TODO: use typesafe data class when possible
bottomSheet(
"${Route.StreamInfo.id}?urlOrId={urlOrId}",
"${Route.StreamInfo}?urlOrId={urlOrId}",
arguments = listOf(navArgument("urlOrId") { defaultValue = "" }),
) { backStackEntry ->
val streamInfoViewModel = hiltViewModel<StreamInfoViewModel>()

val urlOrId = backStackEntry.arguments?.getString("urlOrId")!!

StreamInfo(
urlOrId = urlOrId,
viewModel = streamInfoViewModel,
)
}

composable(Route.Welcome.id) {
val welcomeViewModel = hiltViewModel<WelcomeViewModel>()

composable<Route.Welcome> {
WelcomeScreen(
navigateToHome = { navController.navigate(Route.Home.id) },
viewModel = welcomeViewModel,
navigateToHome = { navController.navigate(Route.Home) },
)
}

composable(
"${Route.Player.id}?urlOrId={urlOrId}",
arguments = listOf(navArgument("urlOrId") { defaultValue = "" }),
) { backStackEntry ->
composable<Route.Player> { backStackEntry ->
val playerViewModel = hiltViewModel<PlayerViewModel>()

val urlOrId = backStackEntry.arguments?.getString("urlOrId")!!
val urlOrId = backStackEntry.toRoute<Route.Player>().urlOrId
val videoId = playerViewModel.getVideoId(urlOrId)

PlayerScreen(videoId, setKeepScreenOn, setFullscreen, playerViewModel)
}

composable(Route.Settings.id) {
val settingsViewModel = hiltViewModel<SettingsViewModel>()

composable<Route.Settings> {
SettingsScreen(
onBackPressed = { navigateBack() },
viewModel = settingsViewModel,
)
}

composable(Route.About.id) {
composable<Route.About> {
AboutScreen(
onBackPressed = { navigateBack() },
navigateToLicenses = { navController.navigate(Route.Licenses.id) },
navigateToWelcome = { navController.navigate(Route.Welcome.id) },
navigateToLicenses = { navController.navigate(Route.Licenses) },
navigateToWelcome = { navController.navigate(Route.Welcome) },
)
}

composable(Route.Licenses.id) {
composable<Route.Licenses> {
LicensesScreen(
onBackPressed = { navigateBack() },
)
Expand Down
25 changes: 17 additions & 8 deletions app/src/main/kotlin/com/livetl/android/ui/navigation/Routes.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package com.livetl.android.ui.navigation

sealed class Route(val id: String) {
data object Home : Route("home")
import kotlinx.serialization.Serializable

data object StreamInfo : Route("stream")
sealed interface Route {
@Serializable
data object Home : Route

data object Welcome : Route("welcome")
@Serializable
data class StreamInfo(val urlOrId: String) : Route

data object Player : Route("player")
@Serializable
data object Welcome : Route

data object Settings : Route("settings")
@Serializable
data class Player(val urlOrId: String) : Route

data object About : Route("about")
@Serializable
data object Settings : Route

data object Licenses : Route("licenses")
@Serializable
data object Licenses : Route

@Serializable
data object About : Route
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.livetl.android.R
import com.livetl.android.data.feed.Stream
import com.livetl.android.ui.common.TabIndicator
Expand All @@ -41,7 +42,7 @@ fun HomeScreen(
navigateToPlayer: (String) -> Unit,
navigateToSettings: () -> Unit,
navigateToAbout: () -> Unit,
viewModel: HomeViewModel,
viewModel: HomeViewModel = hiltViewModel(),
) {
val coroutineScope = rememberCoroutineScope()
val pagerState = rememberPagerState { viewModel.tabs.size }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import coil.compose.AsyncImage
import com.livetl.android.R
import com.livetl.android.data.feed.Stream
Expand All @@ -39,7 +40,7 @@ import kotlinx.coroutines.launch
@Composable
fun StreamInfo(
urlOrId: String,
viewModel: StreamInfoViewModel,
viewModel: StreamInfoViewModel = hiltViewModel(),
) {
val coroutineScope = rememberCoroutineScope()
var loading by remember { mutableStateOf(true) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.livetl.android.R
import com.livetl.android.data.feed.ORGANIZATIONS
import com.livetl.android.util.collectAsState

@Composable
fun SettingsScreen(
onBackPressed: () -> Unit,
viewModel: SettingsViewModel,
viewModel: SettingsViewModel = hiltViewModel(),
) {
val selectedOrganization by viewModel.prefs.feedOrganization().collectAsState()

Expand All @@ -59,9 +60,9 @@ fun SettingsScreen(
) { contentPadding ->
LazyColumn(
modifier =
Modifier
.fillMaxWidth()
.padding(contentPadding),
Modifier
.fillMaxWidth()
.padding(contentPadding),
) {
items(
items = ORGANIZATIONS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import androidx.hilt.navigation.compose.hiltViewModel
import com.livetl.android.data.stream.StreamInfo
import com.livetl.android.ui.common.LoadingIndicator
import com.livetl.android.util.collectAsState
Expand All @@ -33,7 +34,7 @@ fun PlayerScreen(
videoId: String,
setKeepScreenOn: (Boolean) -> Unit,
toggleFullscreen: (Boolean) -> Unit,
viewModel: PlayerViewModel,
viewModel: PlayerViewModel = hiltViewModel(),
) {
val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.livetl.android.R

@Composable
fun WelcomeScreen(
navigateToHome: () -> Unit,
viewModel: WelcomeViewModel,
viewModel: WelcomeViewModel = hiltViewModel(),
) {
Scaffold(
topBar = {
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ compose-activity = { module = "androidx.activity:activity-compose", version = "1
compose-lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.3.1" }

navigation-compose = "androidx.navigation:navigation-compose:2.8.0-beta01"
navigation-accompanist = "com.google.accompanist:accompanist-navigation-material:0.35.1-alpha"
compose-material-navigation = { module = "androidx.compose.material:material-navigation", version = "1.7.0-beta01" }

coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines_version" }
coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines_version" }
Expand Down Expand Up @@ -65,5 +65,5 @@ compose = ["compose-activity", "compose-material", "compose-material-icons-exten
compose-debug = ["compose-ui-tooling-debug"]
coroutines = ["coroutines-core", "coroutines-android"]
ktor = ["ktor-core", "ktor-logging"]
navigation = ["navigation-compose", "navigation-accompanist", "hilt-navigation"]
navigation = ["navigation-compose", "compose-material-navigation", "hilt-navigation"]
preferences = ["preferences-androidx", "preferences-flow"]

0 comments on commit f1211b1

Please sign in to comment.