refactor: pull out ClawAppBar

Also change consumers of ClawBackStack to take delegating references
This commit is contained in:
Harsh Shandilya 2025-05-25 18:28:40 +05:30
parent beb1943ee6
commit 9dce06ff80
4 changed files with 90 additions and 59 deletions

View file

@ -0,0 +1,75 @@
/*
* Copyright © 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.decorations
import android.app.Activity
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import dev.msfjarvis.claw.android.R
import dev.msfjarvis.claw.android.ui.navigation.Destination
import dev.msfjarvis.claw.android.ui.navigation.Search
import dev.msfjarvis.claw.android.ui.navigation.Settings
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ClawAppBar(
activity: Activity?,
isTopLevel: Boolean,
navigateTo: (Destination) -> Unit,
popBackStack: () -> Destination?,
modifier: Modifier = Modifier,
) {
TopAppBar(
modifier = modifier.shadow(8.dp),
navigationIcon = {
if (!isTopLevel) {
IconButton(onClick = { if (popBackStack() == null) activity?.finish() }) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Go back to previous screen",
)
}
} else {
Icon(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = "The app icon for Claw",
modifier = Modifier.size(48.dp),
)
}
},
title = {
if (isTopLevel) {
Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
}
},
actions = {
if (isTopLevel) {
IconButton(onClick = { navigateTo(Search) }) {
Icon(imageVector = Icons.Filled.Search, contentDescription = "Search posts")
}
IconButton(onClick = { navigateTo(Settings) }) {
Icon(imageVector = Icons.Filled.Tune, contentDescription = "Settings")
}
}
},
)
}

View file

@ -31,7 +31,6 @@ import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.HazeStyle
import dev.chrisbanes.haze.hazeEffect
import dev.msfjarvis.claw.android.ui.navigation.AppDestinations
import dev.msfjarvis.claw.android.ui.navigation.ClawBackStack
import dev.msfjarvis.claw.android.ui.navigation.Destination
import dev.msfjarvis.claw.common.ui.FloatingNavigationBar
import kotlinx.collections.immutable.ImmutableList
@ -40,8 +39,9 @@ const val AnimationDuration = 100
@Composable
fun ClawNavigationBar(
backStack: ClawBackStack<Destination>,
items: ImmutableList<NavigationItem>,
currentDestination: Destination?,
navigateTo: (Destination) -> Unit,
isVisible: Boolean,
hazeState: HazeState,
modifier: Modifier = Modifier,
@ -83,7 +83,6 @@ fun ClawNavigationBar(
containerColor =
if (HazeDefaults.blurEnabled()) Color.Transparent else MaterialTheme.colorScheme.surface,
) {
val currentDestination = backStack.firstOrNull()
items.forEach { navItem ->
val isSelected = currentDestination == navItem.destination
NavigationBarItem(
@ -101,7 +100,7 @@ fun ClawNavigationBar(
if (isSelected) {
navItem.listStateResetCallback()
} else {
backStack.add(navItem.destination)
navigateTo(navItem.destination)
}
},
modifier = Modifier.testTag(navItem.label.uppercase()),

View file

@ -21,14 +21,14 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import dev.msfjarvis.claw.android.ui.navigation.ClawBackStack
import dev.msfjarvis.claw.android.ui.navigation.Destination
import kotlinx.collections.immutable.ImmutableList
@Composable
fun ClawNavigationRail(
backStack: ClawBackStack<Destination>,
items: ImmutableList<NavigationItem>,
currentDestination: Destination?,
navigateTo: (Destination) -> Unit,
isVisible: Boolean,
modifier: Modifier = Modifier,
) {
@ -49,7 +49,6 @@ fun ClawNavigationRail(
modifier = Modifier,
) {
NavigationRail(modifier = modifier) {
val currentDestination = backStack.firstOrNull()
Spacer(Modifier.weight(1f))
items.forEach { navItem ->
val isSelected = currentDestination == navItem.destination
@ -68,7 +67,7 @@ fun ClawNavigationRail(
if (isSelected) {
navItem.listStateResetCallback()
} else {
backStack.add(navItem.destination)
navigateTo(navItem.destination)
}
},
modifier = Modifier.testTag(navItem.label.uppercase()),

View file

@ -15,20 +15,11 @@ import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -36,14 +27,9 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation3.runtime.entry
import androidx.navigation3.runtime.entryProvider
@ -54,8 +40,8 @@ import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.hazeSource
import dev.msfjarvis.claw.android.MainActivity
import dev.msfjarvis.claw.android.R
import dev.msfjarvis.claw.android.ui.PostActions
import dev.msfjarvis.claw.android.ui.decorations.ClawAppBar
import dev.msfjarvis.claw.android.ui.decorations.ClawNavigationBar
import dev.msfjarvis.claw.android.ui.decorations.NavigationItem
import dev.msfjarvis.claw.android.ui.lists.DatabasePosts
@ -138,48 +124,20 @@ fun Nav3Screen(
Scaffold(
topBar = {
TopAppBar(
modifier = Modifier.shadow(8.dp),
navigationIcon = {
if (!(clawBackStack.isOnTopLevelDestination())) {
IconButton(
onClick = { if (clawBackStack.removeLastOrNull() == null) activity?.finish() }
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Go back to previous screen",
)
}
} else {
Icon(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = "The app icon for Claw",
modifier = Modifier.size(48.dp),
)
}
},
title = {
if (clawBackStack.isOnTopLevelDestination()) {
Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
}
},
actions = {
if (clawBackStack.isOnTopLevelDestination()) {
IconButton(onClick = { clawBackStack.add(Search) }) {
Icon(imageVector = Icons.Filled.Search, contentDescription = "Search posts")
}
IconButton(onClick = { clawBackStack.add(Settings) }) {
Icon(imageVector = Icons.Filled.Tune, contentDescription = "Settings")
}
}
},
ClawAppBar(
activity = activity,
isTopLevel = clawBackStack.isOnTopLevelDestination(),
navigateTo = { clawBackStack.add(it) },
popBackStack = { clawBackStack.removeLastOrNull() },
)
},
bottomBar = {
val currentDestination = clawBackStack.firstOrNull()
AnimatedVisibility(visible = navigationType == ClawNavigationType.BOTTOM_NAVIGATION) {
ClawNavigationBar(
clawBackStack,
items = navItems,
currentDestination = currentDestination,
navigateTo = { clawBackStack.add(it) },
isVisible = clawBackStack.isOnTopLevelDestination(),
hazeState = hazeState,
)