Skip to content

Commit b80183b

Browse files
committed
Migrate navigation to Compose Destinations
Replaces custom navigation graph implementations with Compose Destinations library. Updates navigation logic, removes obsolete route classes, and annotates screens with destination annotations. Adds Compose Destinations dependencies and provides navigator via CompositionLocal.
1 parent c1e6dec commit b80183b

File tree

17 files changed

+115
-221
lines changed

17 files changed

+115
-221
lines changed

app/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,7 @@ dependencies {
252252
implementation(libs.square.logging.interceptor)
253253
implementation(libs.square.moshi)
254254
ksp(libs.square.moshi.kotlin)
255+
256+
implementation(libs.composedestinations.core)
257+
ksp(libs.composedestinations.ksp)
255258
}

app/src/main/java/com/dergoogler/mmrl/wx/ui/component/ListItems.kt

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable
66
import androidx.compose.ui.platform.LocalUriHandler
77
import androidx.compose.ui.res.painterResource
88
import androidx.compose.ui.unit.dp
9-
import com.dergoogler.mmrl.ext.navigateSingleTopTo
109
import com.dergoogler.mmrl.ext.nullable
1110
import com.dergoogler.mmrl.ui.component.listItem.dsl.ListItemScope
1211
import com.dergoogler.mmrl.ui.component.listItem.dsl.ListItemSlot
@@ -16,35 +15,24 @@ import com.dergoogler.mmrl.ui.component.listItem.dsl.component.SwitchItem
1615
import com.dergoogler.mmrl.ui.component.listItem.dsl.component.item.Description
1716
import com.dergoogler.mmrl.ui.component.listItem.dsl.component.item.Icon
1817
import com.dergoogler.mmrl.ui.component.listItem.dsl.component.item.Title
19-
import com.dergoogler.mmrl.ui.providable.LocalNavController
2018
import com.dergoogler.mmrl.wx.R
2119
import com.dergoogler.mmrl.wx.datastore.providable.LocalUserPreferences
20+
import com.dergoogler.mmrl.wx.ui.providable.LocalDestinationsNavigator
21+
import com.ramcosta.composedestinations.spec.Direction
2222

23-
@Composable
24-
internal fun ListScope.NavButton(
25-
route: String,
26-
@DrawableRes icon: Int? = null,
27-
@StringRes title: Int,
28-
@StringRes desc: Int? = null,
29-
) = NavButton<String>(
30-
route = route,
31-
icon = icon,
32-
title = title,
33-
desc = desc
34-
)
3523

3624
@Composable
37-
internal fun <T : Any> ListScope.NavButton(
25+
internal fun <T : Direction> ListScope.NavButton(
3826
route: T,
3927
@DrawableRes icon: Int? = null,
4028
@StringRes title: Int,
4129
@StringRes desc: Int? = null,
4230
) {
43-
val navController = LocalNavController.current
31+
val navigator = LocalDestinationsNavigator.current
4432

4533
ButtonItem(
4634
onClick = {
47-
navController.navigateSingleTopTo(route)
35+
navigator.navigate(route)
4836
},
4937
content = {
5038
icon.nullable {

app/src/main/java/com/dergoogler/mmrl/wx/ui/navigation/Main.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,26 @@ package com.dergoogler.mmrl.wx.ui.navigation
33
import androidx.annotation.DrawableRes
44
import androidx.annotation.StringRes
55
import com.dergoogler.mmrl.wx.R
6-
import kotlinx.serialization.Serializable
6+
import com.ramcosta.composedestinations.generated.destinations.ModulesScreenDestination
7+
import com.ramcosta.composedestinations.generated.destinations.SettingsScreenDestination
8+
import com.ramcosta.composedestinations.spec.DirectionDestinationSpec
79

8-
@Serializable
9-
sealed class MainRoute(
10+
enum class MainDestination(
11+
val direction: DirectionDestinationSpec,
1012
@StringRes val label: Int,
1113
@DrawableRes val icon: Int,
1214
@DrawableRes val iconFilled: Int,
1315
) {
14-
@Serializable
15-
data object Modules : MainRoute(
16+
Modules(
17+
direction = ModulesScreenDestination,
1618
label = R.string.modules,
1719
icon = R.drawable.stack_2,
1820
iconFilled = R.drawable.stack_2_filled
19-
)
20-
21-
@Serializable
22-
data object Settings : MainRoute(
21+
),
22+
Settings(
23+
direction = SettingsScreenDestination,
2324
label = R.string.settings,
2425
icon = R.drawable.settings,
2526
iconFilled = R.drawable.settings_filled
26-
)
27+
),
2728
}

app/src/main/java/com/dergoogler/mmrl/wx/ui/navigation/graphs/Modules.kt

Lines changed: 0 additions & 73 deletions
This file was deleted.

app/src/main/java/com/dergoogler/mmrl/wx/ui/navigation/graphs/Settings.kt

Lines changed: 0 additions & 56 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.dergoogler.mmrl.wx.ui.providable
2+
3+
import androidx.compose.runtime.staticCompositionLocalOf
4+
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
5+
6+
val LocalDestinationsNavigator = staticCompositionLocalOf<DestinationsNavigator> {
7+
error("CompositionLocal DestinationsNavigator not present")
8+
}

app/src/main/java/com/dergoogler/mmrl/wx/ui/screens/MainScreen.kt

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package com.dergoogler.mmrl.wx.ui.screens
22

33
import android.util.Log
4+
import androidx.compose.animation.AnimatedContentTransitionScope
5+
import androidx.compose.animation.EnterTransition
6+
import androidx.compose.animation.ExitTransition
7+
import androidx.compose.animation.core.tween
8+
import androidx.compose.animation.fadeIn
9+
import androidx.compose.animation.fadeOut
410
import androidx.compose.foundation.layout.WindowInsets
511
import androidx.compose.foundation.layout.imePadding
612
import androidx.compose.foundation.layout.padding
@@ -15,7 +21,6 @@ import androidx.compose.material3.SnackbarHostState
1521
import androidx.compose.material3.Text
1622
import androidx.compose.runtime.Composable
1723
import androidx.compose.runtime.LaunchedEffect
18-
import androidx.compose.runtime.derivedStateOf
1924
import androidx.compose.runtime.getValue
2025
import androidx.compose.runtime.remember
2126
import androidx.compose.ui.Modifier
@@ -24,20 +29,18 @@ import androidx.compose.ui.platform.LocalContext
2429
import androidx.compose.ui.res.painterResource
2530
import androidx.compose.ui.res.stringResource
2631
import androidx.compose.ui.unit.dp
27-
import androidx.navigation.NavDestination.Companion.hierarchy
28-
import androidx.navigation.compose.NavHost
29-
import androidx.navigation.compose.currentBackStackEntryAsState
30-
import com.dergoogler.mmrl.datastore.model.WorkingMode.Companion.isRoot
32+
import androidx.navigation.NavBackStackEntry
3133
import com.dergoogler.mmrl.ext.none
32-
import com.dergoogler.mmrl.platform.PlatformManager
3334
import com.dergoogler.mmrl.ui.providable.LocalNavController
3435
import com.dergoogler.mmrl.wx.App.Companion.TAG
3536
import com.dergoogler.mmrl.wx.datastore.providable.LocalUserPreferences
3637
import com.dergoogler.mmrl.wx.service.PlatformService
37-
import com.dergoogler.mmrl.wx.ui.navigation.MainRoute
38-
import com.dergoogler.mmrl.wx.ui.navigation.graphs.modulesRoute
39-
import com.dergoogler.mmrl.wx.ui.navigation.graphs.settingsRoute
40-
import com.dergoogler.mmrl.wx.util.navigatePopUpTo
38+
import com.dergoogler.mmrl.wx.ui.navigation.MainDestination
39+
import com.dergoogler.mmrl.wx.ui.providable.LocalDestinationsNavigator
40+
import com.ramcosta.composedestinations.DestinationsNavHost
41+
import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle
42+
import com.ramcosta.composedestinations.generated.NavGraphs
43+
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
4144

4245
@Composable
4346
fun MainScreen() {
@@ -47,17 +50,6 @@ fun MainScreen() {
4750
val navController = LocalNavController.current
4851
val snackbarHostState = remember { SnackbarHostState() }
4952

50-
val isRoot = userPreferences.workingMode.isRoot && PlatformManager.isAlive
51-
52-
val mainScreens by remember(isRoot) {
53-
derivedStateOf {
54-
return@derivedStateOf listOf(
55-
MainRoute.Modules,
56-
MainRoute.Settings
57-
)
58-
}
59-
}
60-
6153
LaunchedEffect(Unit) {
6254
val platform = userPreferences.workingMode.toPlatform()
6355

@@ -73,29 +65,29 @@ fun MainScreen() {
7365

7466
Scaffold(
7567
bottomBar = {
76-
BottomNav(mainScreens)
68+
BottomNav()
7769
},
7870
snackbarHost = { SnackbarHost(snackbarHostState) },
7971
contentWindowInsets = WindowInsets.none
8072
) { paddingValues ->
81-
NavHost(
73+
DestinationsNavHost(
8274
modifier = Modifier.padding(bottom = paddingValues.calculateBottomPadding()),
75+
navGraph = NavGraphs.root,
8376
navController = navController,
84-
startDestination = MainRoute.Modules
85-
) {
86-
modulesRoute()
87-
settingsRoute()
88-
}
77+
defaultTransitions = object : NavHostAnimatedDestinationStyle() {
78+
override val enterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition
79+
get() = { fadeIn(animationSpec = tween(340)) }
80+
override val exitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition
81+
get() = { fadeOut(animationSpec = tween(340)) }
82+
}
83+
)
8984
}
9085
}
9186

9287
@Composable
93-
private fun BottomNav(
94-
mainScreens: List<MainRoute>,
95-
) {
88+
private fun BottomNav() {
9689
val navController = LocalNavController.current
97-
val navBackStackEntry by navController.currentBackStackEntryAsState()
98-
val currentDestination = navBackStackEntry?.destination
90+
val navigator = LocalDestinationsNavigator.current
9991

10092
NavigationBar(
10193
modifier = Modifier
@@ -107,15 +99,14 @@ private fun BottomNav(
10799
)
108100
)
109101
) {
110-
mainScreens.forEach { screen ->
111-
val selected =
112-
currentDestination?.hierarchy?.any { it.route == screen::class.java.name } == true
102+
MainDestination.entries.forEach { screen ->
103+
val isSelected by navController.isRouteOnBackStackAsState(screen.direction)
113104

114105
NavigationBarItem(
115106
icon = {
116107
Icon(
117108
painter = painterResource(
118-
id = if (selected) {
109+
id = if (isSelected) {
119110
screen.iconFilled
120111
} else {
121112
screen.icon
@@ -131,13 +122,19 @@ private fun BottomNav(
131122
)
132123
},
133124
alwaysShowLabel = true,
134-
selected = selected,
125+
selected = isSelected,
135126
onClick = {
136-
if (selected) return@NavigationBarItem
127+
if (isSelected) {
128+
navigator.popBackStack(screen.direction, false)
129+
}
137130

138-
navController.navigatePopUpTo(
139-
route = screen,
140-
)
131+
navigator.navigate(screen.direction) {
132+
popUpTo(NavGraphs.root) {
133+
saveState = true
134+
}
135+
launchSingleTop = true
136+
restoreState = true
137+
}
141138
}
142139
)
143140
}

0 commit comments

Comments
 (0)