@@ -6,36 +6,43 @@ import android.os.Bundle
66import androidx.activity.ComponentActivity
77import androidx.activity.compose.setContent
88import androidx.activity.enableEdgeToEdge
9- import androidx.compose.foundation.layout.Column
9+ import androidx.compose.animation.AnimatedVisibility
10+ import androidx.compose.animation.slideInVertically
11+ import androidx.compose.animation.slideOutVertically
12+ import androidx.compose.foundation.layout.WindowInsets
13+ import androidx.compose.material3.BottomAppBar
14+ import androidx.compose.material3.BottomAppBarDefaults
1015import androidx.compose.material3.ExperimentalMaterial3Api
16+ import androidx.compose.material3.Icon
17+ import androidx.compose.material3.NavigationBarItem
18+ import androidx.compose.material3.Scaffold
1119import androidx.compose.material3.Surface
1220import androidx.compose.material3.Text
1321import androidx.compose.runtime.Composable
22+ import androidx.compose.runtime.CompositionLocalProvider
23+ import androidx.compose.runtime.compositionLocalOf
1424import androidx.compose.runtime.getValue
15- import androidx.compose.runtime.mutableStateListOf
1625import androidx.compose.runtime.remember
1726import androidx.compose.ui.Modifier
27+ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
28+ import androidx.compose.ui.platform.LocalHapticFeedback
29+ import androidx.compose.ui.platform.LocalLayoutDirection
30+ import androidx.compose.ui.res.stringResource
1831import androidx.lifecycle.compose.collectAsStateWithLifecycle
1932import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
2033import androidx.navigation3.runtime.NavEntry
2134import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator
2235import androidx.navigation3.ui.NavDisplay
2336import androidx.navigation3.ui.rememberSceneSetupNavEntryDecorator
2437import com.yogeshpaliyal.deepr.preference.AppPreferenceDataStore
25- import com.yogeshpaliyal.deepr.ui.screens.AboutUs
26- import com.yogeshpaliyal.deepr.ui.screens.AboutUsScreen
27- import com.yogeshpaliyal.deepr.ui.screens.BackupScreen
28- import com.yogeshpaliyal.deepr.ui.screens.BackupScreenContent
29- import com.yogeshpaliyal.deepr.ui.screens.LocalNetworkServer
30- import com.yogeshpaliyal.deepr.ui.screens.LocalNetworkServerScreen
31- import com.yogeshpaliyal.deepr.ui.screens.RestoreScreen
32- import com.yogeshpaliyal.deepr.ui.screens.RestoreScreenContent
38+ import com.yogeshpaliyal.deepr.ui.BaseScreen
39+ import com.yogeshpaliyal.deepr.ui.LocalNavigator
40+ import com.yogeshpaliyal.deepr.ui.Screen
41+ import com.yogeshpaliyal.deepr.ui.TopLevelBackStack
42+ import com.yogeshpaliyal.deepr.ui.TopLevelRoute
3343import com.yogeshpaliyal.deepr.ui.screens.Settings
34- import com.yogeshpaliyal.deepr.ui.screens.SettingsScreen
35- import com.yogeshpaliyal.deepr.ui.screens.TransferLinkLocalNetworkServer
36- import com.yogeshpaliyal.deepr.ui.screens.TransferLinkLocalServerScreen
37- import com.yogeshpaliyal.deepr.ui.screens.home.Home
38- import com.yogeshpaliyal.deepr.ui.screens.home.HomeScreen
44+ import com.yogeshpaliyal.deepr.ui.screens.home.Dashboard2
45+ import com.yogeshpaliyal.deepr.ui.screens.home.TagSelectionScreen
3946import com.yogeshpaliyal.deepr.ui.theme.DeeprTheme
4047import com.yogeshpaliyal.deepr.util.LanguageUtil
4148import kotlinx.coroutines.flow.MutableStateFlow
@@ -81,7 +88,9 @@ class MainActivity : ComponentActivity() {
8188
8289 setContent {
8390 val preferenceDataStore = remember { AppPreferenceDataStore (this ) }
84- val themeMode by preferenceDataStore.getThemeMode.collectAsStateWithLifecycle(initialValue = " system" )
91+ val themeMode by preferenceDataStore.getThemeMode.collectAsStateWithLifecycle(
92+ initialValue = " system" ,
93+ )
8594
8695 DeeprTheme (themeMode = themeMode) {
8796 Surface {
@@ -123,70 +132,96 @@ class MainActivity : ComponentActivity() {
123132 }
124133}
125134
135+ private val TOP_LEVEL_ROUTES : List <TopLevelRoute > =
136+ listOf (Dashboard2 (), TagSelectionScreen , Settings )
137+
138+ val LocalSharedText =
139+ compositionLocalOf<Pair <SharedLink ?, () - > Unit > ? > { null }
140+
141+ @OptIn(ExperimentalMaterial3Api ::class )
126142@Composable
127143fun Dashboard (
128144 modifier : Modifier = Modifier ,
129145 sharedText : SharedLink ? = null,
130146 resetSharedText : () -> Unit ,
131147) {
132- val backStack = remember(sharedText) { mutableStateListOf<Any >(Home ) }
133-
134- Column (modifier = modifier) {
135- NavDisplay (
136- backStack = backStack,
137- entryDecorators =
138- listOf (
139- // Add the default decorators for managing scenes and saving state
140- rememberSceneSetupNavEntryDecorator(),
141- rememberSavedStateNavEntryDecorator(),
142- // Then add the view model store decorator
143- rememberViewModelStoreNavEntryDecorator(),
144- ),
145- onBack = { backStack.removeLastOrNull() },
146- entryProvider = { key ->
147- when (key) {
148- is Home ->
149- NavEntry (key) {
150- HomeScreen (
151- backStack,
152- sharedText = sharedText,
153- resetSharedText = resetSharedText,
154- )
155- }
156-
157- is Settings ->
158- NavEntry (key) {
159- SettingsScreen (backStack)
160- }
161-
162- is AboutUs ->
163- NavEntry (key) {
164- AboutUsScreen (backStack)
165- }
166-
167- is LocalNetworkServer ->
168- NavEntry (key) {
169- LocalNetworkServerScreen (backStack)
170- }
171-
172- is TransferLinkLocalNetworkServer ->
173- NavEntry (key) {
174- TransferLinkLocalServerScreen (backStack)
175- }
176-
177- is BackupScreen ->
178- NavEntry (key) {
179- BackupScreenContent (backStack)
148+ val backStack =
149+ remember {
150+ TopLevelBackStack <BaseScreen >(
151+ Dashboard2 (),
152+ )
153+ }
154+ val current = backStack.getLast()
155+ val scrollBehavior = BottomAppBarDefaults .exitAlwaysScrollBehavior()
156+ val hapticFeedback = LocalHapticFeedback .current
157+ val layoutDirection = LocalLayoutDirection .current
158+
159+ CompositionLocalProvider (LocalSharedText provides Pair (sharedText, resetSharedText)) {
160+ CompositionLocalProvider (LocalNavigator provides backStack) {
161+ Scaffold (
162+ modifier = modifier,
163+ bottomBar = {
164+ AnimatedVisibility (
165+ (TOP_LEVEL_ROUTES .any { it::class == current::class }),
166+ enter = slideInVertically(initialOffsetY = { it }),
167+ exit = slideOutVertically(targetOffsetY = { it }),
168+ ) {
169+ BottomAppBar (scrollBehavior = scrollBehavior) {
170+ TOP_LEVEL_ROUTES .forEach { topLevelRoute ->
171+ val isSelected =
172+ topLevelRoute::class == backStack.topLevelKey::class
173+ NavigationBarItem (
174+ selected = isSelected,
175+ onClick = {
176+ hapticFeedback.performHapticFeedback(HapticFeedbackType .ContextClick )
177+ backStack.addTopLevel(topLevelRoute)
178+ },
179+ label = {
180+ Text (stringResource(topLevelRoute.label))
181+ },
182+ icon = {
183+ Icon (
184+ imageVector = topLevelRoute.icon,
185+ contentDescription = null ,
186+ )
187+ },
188+ )
189+ }
180190 }
181-
182- is RestoreScreen ->
183- NavEntry (key) {
184- RestoreScreenContent (backStack)
191+ }
192+ },
193+ ) { contentPadding ->
194+ NavDisplay (
195+ backStack = backStack.backStack,
196+ entryDecorators =
197+ listOf (
198+ // Add the default decorators for managing scenes and saving state
199+ rememberSceneSetupNavEntryDecorator(),
200+ rememberSavedStateNavEntryDecorator(),
201+ // Then add the view model store decorator
202+ rememberViewModelStoreNavEntryDecorator(),
203+ ),
204+ onBack = {
205+ backStack.removeLast()
206+ },
207+ entryProvider = {
208+ NavEntry (it) { entryItem ->
209+ if (entryItem is TopLevelRoute ) {
210+ entryItem.Content (
211+ WindowInsets (
212+ left = contentPadding.calculateLeftPadding(layoutDirection),
213+ right = contentPadding.calculateRightPadding(layoutDirection),
214+ top = contentPadding.calculateTopPadding(),
215+ bottom = contentPadding.calculateBottomPadding(),
216+ ),
217+ )
218+ } else if (entryItem is Screen ) {
219+ entryItem.Content ()
220+ }
185221 }
186-
187- else -> NavEntry (Unit ) { Text (" Unknown route" ) }
188- }
189- },
190- )
222+ },
223+ )
224+ }
225+ }
191226 }
192227}
0 commit comments