Skip to content

Commit

Permalink
refactor(android): migrate to navigation safe-args
Browse files Browse the repository at this point in the history
  • Loading branch information
msfjarvis committed May 2, 2024
1 parent 9361c7e commit 127a692
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 165 deletions.
2 changes: 2 additions & 0 deletions android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ plugins {
alias(libs.plugins.baselineprofile)
alias(libs.plugins.licensee)
alias(libs.plugins.tracelog)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.navigation.safeargs)
}

android {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2022-2023 Harsh Shandilya.
* Copyright © 2022-2024 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
Expand All @@ -22,7 +22,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import androidx.navigation.compose.currentBackStackEntryAsState
import dev.msfjarvis.claw.android.ui.matches
import dev.msfjarvis.claw.android.ui.navigation.Destination
import kotlinx.collections.immutable.ImmutableList

const val AnimationDuration = 100
Expand Down Expand Up @@ -51,28 +53,29 @@ fun ClawNavigationBar(
modifier = Modifier,
) {
NavigationBar(modifier = modifier) {
val navBackStackEntry = navController.currentBackStackEntryAsState().value
val currentDestination = navBackStackEntry?.destination
items.forEach { navItem ->
val isCurrentDestination = navController.currentDestination?.route == navItem.route
val isSelected = currentDestination.matches(navItem.destination)
NavigationBarItem(
icon = {
Crossfade(isCurrentDestination, label = "nav-label") {
Crossfade(isSelected, label = "nav-label") {
Icon(
imageVector = if (it) navItem.selectedIcon else navItem.icon,
contentDescription = navItem.label.replaceFirstChar(Char::uppercase),
)
}
},
label = { Text(text = navItem.label) },
selected = isCurrentDestination,
selected = isSelected,
onClick = {
if (isCurrentDestination) {
if (isSelected) {
navItem.listStateResetCallback()
} else {
navController.graph.startDestinationRoute?.let { startDestination ->
navController.popBackStack(startDestination, false)
}
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
navController.navigate(navItem.destination) {
popUpTo(navController.graph.startDestinationId) { saveState = true }
launchSingleTop = true
restoreState = true
}
}
},
Expand All @@ -85,7 +88,7 @@ fun ClawNavigationBar(

class NavigationItem(
val label: String,
val route: String,
val destination: Destination,
val icon: ImageVector,
val selectedIcon: ImageVector,
val listStateResetCallback: () -> Unit,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2022-2023 Harsh Shandilya.
* Copyright © 2022-2024 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
Expand All @@ -22,7 +22,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import androidx.navigation.compose.currentBackStackEntryAsState
import dev.msfjarvis.claw.android.ui.matches
import kotlinx.collections.immutable.ImmutableList

@Composable
Expand All @@ -49,29 +50,30 @@ fun ClawNavigationRail(
modifier = Modifier,
) {
NavigationRail(modifier = modifier) {
val navBackStackEntry = navController.currentBackStackEntryAsState().value
val currentDestination = navBackStackEntry?.destination
Spacer(Modifier.weight(1f))
items.forEach { navItem ->
val isCurrentDestination = navController.currentDestination?.route == navItem.route
val isSelected = currentDestination.matches(navItem.destination)
NavigationRailItem(
icon = {
Crossfade(isCurrentDestination, label = "nav-label") {
Crossfade(isSelected, label = "nav-label") {
Icon(
imageVector = if (it) navItem.selectedIcon else navItem.icon,
contentDescription = navItem.label.replaceFirstChar(Char::uppercase),
)
}
},
label = { Text(text = navItem.label) },
selected = isCurrentDestination,
selected = isSelected,
onClick = {
if (isCurrentDestination) {
if (isSelected) {
navItem.listStateResetCallback()
} else {
navController.graph.startDestinationRoute?.let { startDestination ->
navController.popBackStack(startDestination, false)
}
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
navController.navigate(navItem.destination) {
popUpTo(navController.graph.startDestinationId) { saveState = true }
launchSingleTop = true
restoreState = true
}
}
},
Expand Down
30 changes: 25 additions & 5 deletions android/src/main/kotlin/dev/msfjarvis/claw/android/ui/ext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.NavController
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavDestination.Companion.hierarchy
import dev.msfjarvis.claw.android.ui.navigation.Comments
import dev.msfjarvis.claw.android.ui.navigation.Destination
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
import dev.msfjarvis.claw.common.posts.PostActions
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import dev.msfjarvis.claw.model.LinkMetadata
import dev.msfjarvis.claw.model.UIPost
import kotlinx.collections.immutable.ImmutableList

fun Context.getActivity(): ComponentActivity? {
return when (this) {
Expand All @@ -42,10 +47,7 @@ fun rememberPostActions(

override fun viewComments(postId: String) {
viewModel.markPostAsRead(postId)
val currentRoute = navController.currentDestination?.route
val newRoute =
Destinations.Comments.route.replace(Destinations.Comments.PLACEHOLDER, postId)
if (currentRoute != Destinations.Comments.route) navController.navigate(newRoute)
navController.navigate(Comments(postId))
}

override fun viewCommentsPage(post: UIPost) {
Expand All @@ -66,3 +68,21 @@ fun rememberPostActions(
}
}
}

/**
* Walk through the [NavDestination]'s [hierarchy] to see if it has any destination that matches the
* route defined by [dest].
*/
fun NavDestination?.matches(dest: Destination): Boolean {
return this?.hierarchy?.any { it.hasRoute(dest::class) } == true
}

/** Check if this [NavDestination] [matches] any of the potential navigation [destinations]. */
fun NavDestination?.any(destinations: ImmutableList<Destination>): Boolean {
return destinations.any { this?.matches(it) == true }
}

/** Check if this [NavDestination] [matches] none of the potential navigation [destinations]. */
fun NavDestination?.none(destinations: ImmutableList<Destination>): Boolean {
return destinations.none { this?.matches(it) == true }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright © 2024 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.android.ui.navigation

import kotlinx.serialization.Serializable

sealed interface Destination

@Serializable data object Hottest : Destination

@Serializable data object Newest : Destination

@Serializable data object Saved : Destination

@Serializable data class Comments(val postId: String) : Destination

@Serializable data class User(val username: String) : Destination

@Serializable data object Search : Destination

@Serializable data object Settings : Destination

@Serializable data object AboutLibraries : Destination

This file was deleted.

Loading

0 comments on commit 127a692

Please sign in to comment.