Skip to content

Commit 70e3d31

Browse files
author
Josh
committed
started working on nav3 split scene
1 parent bb208ed commit 70e3d31

13 files changed

Lines changed: 174 additions & 41 deletions

File tree

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ dependencies {
118118
implementation(libs.androidx.ui.graphics)
119119
implementation(libs.androidx.ui.tooling.preview)
120120
implementation(libs.androidx.material3)
121+
implementation(libs.androidx.material3.adaptive.navigation)
121122
implementation(libs.androidx.material.icons)
122123
implementation(libs.androidx.material.icons.extended)
123124
implementation(libs.androidx.nav3.runtime)

app/src/main/java/net/frozendevelopment/openletters/MainActivity.kt

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,31 @@ import androidx.compose.foundation.layout.statusBarsPadding
1515
import androidx.compose.foundation.layout.windowInsetsPadding
1616
import androidx.compose.material3.DrawerValue
1717
import androidx.compose.material3.Scaffold
18+
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
1819
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
20+
import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective
21+
import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior
22+
import androidx.compose.material3.adaptive.navigation3.rememberSupportingPaneSceneStrategy
1923
import androidx.compose.material3.rememberDrawerState
2024
import androidx.compose.runtime.CompositionLocalProvider
2125
import androidx.compose.runtime.getValue
2226
import androidx.compose.runtime.remember
2327
import androidx.compose.runtime.rememberCoroutineScope
2428
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.unit.dp
2530
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
2631
import androidx.lifecycle.compose.collectAsStateWithLifecycle
32+
import androidx.navigation3.runtime.NavKey
2733
import androidx.navigation3.runtime.entryProvider
34+
import androidx.navigation3.scene.SceneStrategy
35+
import androidx.navigation3.scene.SinglePaneSceneStrategy
2836
import androidx.navigation3.ui.NavDisplay
37+
import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_MEDIUM_LOWER_BOUND
2938
import androidx.window.core.layout.WindowWidthSizeClass
3039
import kotlinx.coroutines.launch
3140
import net.frozendevelopment.openletters.data.sqldelight.LetterQueries
41+
import net.frozendevelopment.openletters.extensions.EntryProvider
42+
import net.frozendevelopment.openletters.extensions.koinEntryProvider
3243
import net.frozendevelopment.openletters.feature.category.form.CategoryFormDestination
3344
import net.frozendevelopment.openletters.feature.category.manage.ManageCategoryDestination
3445
import net.frozendevelopment.openletters.feature.letter.list.LetterListDestination
@@ -37,13 +48,12 @@ import net.frozendevelopment.openletters.feature.reminder.list.ReminderListDesti
3748
import net.frozendevelopment.openletters.feature.settings.SettingsDestination
3849
import net.frozendevelopment.openletters.ui.animation.popTransitionSpec
3950
import net.frozendevelopment.openletters.ui.animation.pushTransitionSpec
40-
import net.frozendevelopment.openletters.ui.navigation.EntryProvider
4151
import net.frozendevelopment.openletters.ui.navigation.LettersNavDrawer
4252
import net.frozendevelopment.openletters.ui.navigation.LocalDrawerState
4353
import net.frozendevelopment.openletters.ui.navigation.LocalNavigationState
4454
import net.frozendevelopment.openletters.ui.navigation.LocalNavigator
4555
import net.frozendevelopment.openletters.ui.navigation.Navigator
46-
import net.frozendevelopment.openletters.ui.navigation.koinEntryProvider
56+
import net.frozendevelopment.openletters.ui.navigation.rememberListDetailSceneStrategy
4757
import net.frozendevelopment.openletters.ui.navigation.rememberNavigationState
4858
import net.frozendevelopment.openletters.ui.navigation.toEntries
4959
import net.frozendevelopment.openletters.ui.theme.OpenLettersTheme
@@ -55,7 +65,7 @@ class MainActivity : ComponentActivity() {
5565
private val themeManager: ThemeManagerType by inject()
5666
private val letterQueries: LetterQueries by inject()
5767

58-
@OptIn(KoinExperimentalAPI::class)
68+
@OptIn(KoinExperimentalAPI::class, ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3AdaptiveApi::class)
5969
override fun onCreate(savedInstanceState: Bundle?) {
6070
installSplashScreen()
6171

@@ -65,28 +75,39 @@ class MainActivity : ComponentActivity() {
6575

6676
setContent {
6777
val currentTheme by themeManager.current.collectAsStateWithLifecycle()
78+
val listDetailSceneStrategy = rememberListDetailSceneStrategy<NavKey>()
79+
80+
val coroutineScope = rememberCoroutineScope()
81+
val drawerState = rememberDrawerState(DrawerValue.Closed)
82+
val navigationState = rememberNavigationState(
83+
LetterListDestination,
84+
setOf(
85+
LetterListDestination,
86+
ManageCategoryDestination,
87+
ReminderListDestination,
88+
),
89+
)
90+
val navigator = remember { Navigator(navigationState) }
91+
val entryProvider: EntryProvider = koinEntryProvider()
92+
93+
val windowAdaptiveInfo = currentWindowAdaptiveInfo()
94+
val directive = remember(windowAdaptiveInfo) {
95+
calculatePaneScaffoldDirective(windowAdaptiveInfo)
96+
.copy(horizontalPartitionSpacerSize = 0.dp, verticalPartitionSpacerSize = 0.dp)
97+
}
98+
99+
// Override the defaults so that the supporting pane can be dismissed by pressing back.
100+
// See b/445826749
101+
val supportingPaneStrategy = rememberSupportingPaneSceneStrategy<NavKey>(
102+
backNavigationBehavior = BackNavigationBehavior.PopUntilCurrentDestinationChange,
103+
directive = directive
104+
)
105+
68106

69107
OpenLettersTheme(
70108
appTheme = currentTheme.first,
71109
colorPalette = currentTheme.second,
72110
) {
73-
val coroutineScope = rememberCoroutineScope()
74-
val drawerState = rememberDrawerState(DrawerValue.Closed)
75-
val navigationState = rememberNavigationState(
76-
LetterListDestination,
77-
setOf(
78-
LetterListDestination,
79-
ManageCategoryDestination,
80-
ReminderListDestination,
81-
),
82-
)
83-
val navigator = remember { Navigator(navigationState) }
84-
val entryProvider: EntryProvider = koinEntryProvider()
85-
86-
// lock the app to portrait for phone users
87-
if (currentWindowAdaptiveInfo().windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT) {
88-
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
89-
}
90111

91112
LettersNavDrawer(
92113
drawerState = drawerState,
@@ -134,10 +155,7 @@ class MainActivity : ComponentActivity() {
134155
) {
135156
NavDisplay(
136157
entries = navigationState.toEntries(entryProvider),
137-
// entryDecorators = listOf(
138-
// rememberSaveableStateHolderNavEntryDecorator(),
139-
// rememberViewModelStoreNavEntryDecorator()
140-
// ),
158+
sceneStrategy = supportingPaneStrategy,
141159
onBack = { navigator.pop() },
142160
transitionSpec = { pushTransitionSpec() },
143161
popTransitionSpec = { popTransitionSpec() },

app/src/main/java/net/frozendevelopment/openletters/extensions/KoinExtensions.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import org.koin.core.module._singleInstanceFactory
1717
import org.koin.core.qualifier.named
1818
import org.koin.core.scope.Scope
1919
import org.koin.dsl.ScopeDSL
20-
import org.koin.dsl.navigation3.navigation
20+
import net.frozendevelopment.openletters.extensions.navigation
2121

2222
/**
2323
* Declares a scoped navigation entry within a Koin scope DSL.
@@ -45,15 +45,16 @@ import org.koin.dsl.navigation3.navigation
4545
@KoinExperimentalAPI
4646
@KoinDslMarker
4747
@OptIn(KoinInternalApi::class)
48-
inline fun <reified T : NavKey> ScopeDSL.navigation(
48+
inline fun <reified T : Any> ScopeDSL.navigation(
4949
metadata: Map<String, Any> = emptyMap(),
5050
noinline definition: @Composable Scope.(T) -> Unit,
5151
): KoinDefinition<EntryProviderInstaller> {
5252
val def = _scopedInstanceFactory<EntryProviderInstaller>(named<T>(), {
53-
val scope = this {
53+
val scope = this
54+
{
5455
entry<T>(
5556
metadata = metadata,
56-
content = { t -> definition(scope, t) },
57+
content = { t -> definition(scope, t) }
5758
)
5859
}
5960
}, scopeQualifier)
@@ -92,17 +93,19 @@ inline fun <reified T : Any> Module.navigation(
9293
noinline definition: @Composable Scope.(T) -> Unit,
9394
): KoinDefinition<EntryProviderInstaller> {
9495
val def = _singleInstanceFactory<EntryProviderInstaller>(named<T>(), {
95-
val scope = this {
96+
val scope = this
97+
{
9698
entry<T>(
9799
metadata = metadata,
98-
content = { t -> definition(scope, t) },
100+
content = { t -> definition(scope, t) }
99101
)
100102
}
101103
})
102104
indexPrimaryType(def)
103105
return KoinDefinition(this, def)
104106
}
105107

108+
106109
typealias EntryProvider = (NavKey) -> NavEntry<NavKey>
107110

108111
@OptIn(KoinExperimentalAPI::class, KoinInternalApi::class)

app/src/main/java/net/frozendevelopment/openletters/feature/category/form/CategoryFormView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import org.koin.compose.viewmodel.koinViewModel
5151
import org.koin.core.annotation.KoinExperimentalAPI
5252
import org.koin.core.module.Module
5353
import org.koin.core.parameter.parametersOf
54-
import org.koin.dsl.navigation3.navigation
54+
import net.frozendevelopment.openletters.extensions.navigation
5555

5656
@Serializable
5757
data class CategoryFormDestination(

app/src/main/java/net/frozendevelopment/openletters/feature/letter/detail/LetterDetailView.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import androidx.compose.material3.IconButton
2626
import androidx.compose.material3.MaterialTheme
2727
import androidx.compose.material3.Surface
2828
import androidx.compose.material3.Text
29+
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
30+
import androidx.compose.material3.adaptive.navigation3.SupportingPaneSceneStrategy
2931
import androidx.compose.runtime.Composable
3032
import androidx.compose.runtime.getValue
3133
import androidx.compose.runtime.mutableStateOf
@@ -52,27 +54,31 @@ import net.frozendevelopment.openletters.data.sqldelight.models.CategoryId
5254
import net.frozendevelopment.openletters.data.sqldelight.models.DocumentId
5355
import net.frozendevelopment.openletters.data.sqldelight.models.LetterId
5456
import net.frozendevelopment.openletters.extensions.dateString
57+
import net.frozendevelopment.openletters.extensions.navigation
5558
import net.frozendevelopment.openletters.feature.letter.image.ImageDestination
5659
import net.frozendevelopment.openletters.feature.letter.scan.ScanLetterDestination
5760
import net.frozendevelopment.openletters.feature.reminder.form.ReminderFormDestination
5861
import net.frozendevelopment.openletters.ui.components.BrokenImageView
5962
import net.frozendevelopment.openletters.ui.components.CategoryPill
6063
import net.frozendevelopment.openletters.ui.components.LazyImageView
64+
import net.frozendevelopment.openletters.ui.navigation.ListDetailScene.Companion.detailPane
6165
import net.frozendevelopment.openletters.ui.navigation.LocalNavigator
6266
import net.frozendevelopment.openletters.ui.theme.OpenLettersTheme
6367
import org.koin.compose.viewmodel.koinViewModel
6468
import org.koin.core.annotation.KoinExperimentalAPI
6569
import org.koin.core.module.Module
6670
import org.koin.core.parameter.parametersOf
67-
import org.koin.dsl.navigation3.navigation
71+
6872

6973
@Serializable
7074
data class LetterDetailDestination(
7175
val letterId: LetterId,
7276
) : NavKey
7377

74-
@OptIn(KoinExperimentalAPI::class)
75-
fun Module.letterDetailNavigation() = navigation<LetterDetailDestination> { route ->
78+
@OptIn(KoinExperimentalAPI::class, ExperimentalMaterial3AdaptiveApi::class)
79+
fun Module.letterDetailNavigation() = navigation<LetterDetailDestination>(
80+
metadata = SupportingPaneSceneStrategy.supportingPane()
81+
) { route ->
7682
val navigator = LocalNavigator.current
7783
val viewModel: LetterDetailViewModel = koinViewModel { parametersOf(route.letterId) }
7884
val state by viewModel.stateFlow.collectAsStateWithLifecycle()

app/src/main/java/net/frozendevelopment/openletters/feature/letter/image/ImageView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import net.frozendevelopment.openletters.R
3939
import net.frozendevelopment.openletters.ui.components.LazyImageView
4040
import org.koin.core.annotation.KoinExperimentalAPI
4141
import org.koin.core.module.Module
42-
import org.koin.dsl.navigation3.navigation
42+
import net.frozendevelopment.openletters.extensions.navigation
4343

4444
@Serializable
4545
data class ImageDestination(

app/src/main/java/net/frozendevelopment/openletters/feature/letter/list/LetterListView.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import androidx.compose.foundation.layout.padding
99
import androidx.compose.material3.CircularProgressIndicator
1010
import androidx.compose.material3.MaterialTheme
1111
import androidx.compose.material3.Surface
12+
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
13+
import androidx.compose.material3.adaptive.navigation3.SupportingPaneSceneStrategy
1214
import androidx.compose.runtime.Composable
1315
import androidx.compose.runtime.getValue
1416
import androidx.compose.runtime.rememberCoroutineScope
@@ -31,6 +33,7 @@ import net.frozendevelopment.openletters.feature.letter.list.ui.LetterList
3133
import net.frozendevelopment.openletters.feature.letter.scan.ScanLetterDestination
3234
import net.frozendevelopment.openletters.feature.reminder.detail.ReminderDetailDestination
3335
import net.frozendevelopment.openletters.feature.reminder.form.ReminderFormDestination
36+
import net.frozendevelopment.openletters.ui.navigation.ListDetailScene.Companion.listPane
3437
import net.frozendevelopment.openletters.ui.navigation.LocalDrawerState
3538
import net.frozendevelopment.openletters.ui.navigation.LocalNavigator
3639
import net.frozendevelopment.openletters.ui.theme.OpenLettersTheme
@@ -41,11 +44,11 @@ import org.koin.core.module.Module
4144
@Serializable
4245
data object LetterListDestination : NavKey
4346

44-
@OptIn(KoinExperimentalAPI::class)
47+
@OptIn(KoinExperimentalAPI::class, ExperimentalMaterial3AdaptiveApi::class)
4548
fun Module.letterListNavigation() = navigation<LetterListDestination>(
4649
metadata = NavDisplay.transitionSpec {
4750
EnterTransition.None togetherWith ExitTransition.None
48-
},
51+
} + SupportingPaneSceneStrategy.mainPane()
4952
) { route ->
5053
val drawerState = LocalDrawerState.current
5154
val navigator = LocalNavigator.current

app/src/main/java/net/frozendevelopment/openletters/feature/letter/scan/ScanLetterView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ import org.koin.compose.viewmodel.koinViewModel
7272
import org.koin.core.annotation.KoinExperimentalAPI
7373
import org.koin.core.module.Module
7474
import org.koin.core.parameter.parametersOf
75-
import org.koin.dsl.navigation3.navigation
75+
import net.frozendevelopment.openletters.extensions.navigation
7676
import java.time.LocalDateTime
7777

7878
@Serializable

app/src/main/java/net/frozendevelopment/openletters/feature/reminder/detail/ReminderDetailView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ import org.koin.compose.viewmodel.koinViewModel
6060
import org.koin.core.annotation.KoinExperimentalAPI
6161
import org.koin.core.module.Module
6262
import org.koin.core.parameter.parametersOf
63-
import org.koin.dsl.navigation3.navigation
63+
import net.frozendevelopment.openletters.extensions.navigation
6464

6565
@Serializable
6666
data class ReminderDetailDestination(

app/src/main/java/net/frozendevelopment/openletters/feature/reminder/form/ReminderFormView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ import org.koin.compose.viewmodel.koinViewModel
6969
import org.koin.core.annotation.KoinExperimentalAPI
7070
import org.koin.core.module.Module
7171
import org.koin.core.parameter.parametersOf
72-
import org.koin.dsl.navigation3.navigation
72+
import net.frozendevelopment.openletters.extensions.navigation
7373
import java.text.SimpleDateFormat
7474
import java.util.Date
7575
import java.util.Locale

0 commit comments

Comments
 (0)