diff --git a/.editorconfig b/.editorconfig index 74c7bcd9..ab99e32e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,4 +4,9 @@ root = true charset = utf-8 insert_final_newline = true max_line_length = 120 -end_of_line = crlf \ No newline at end of file +end_of_line = crlf + +[*.{kt,kts}] +ktlint_code_style = intellij_idea +ktlint_function_naming_ignore_when_annotated_with = Composable +ktlint_standard_filename = disabled \ No newline at end of file diff --git a/.gitignore b/.gitignore index f93288af..c42215a2 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,5 @@ google-services.json # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* replay_pid* + +*.DS_Store diff --git a/build-config/src/main/kotlin/configuration/configure-ktlint.gradle.kts b/build-config/src/main/kotlin/configuration/configure-ktlint.gradle.kts index 14f9b0b9..66430b22 100644 --- a/build-config/src/main/kotlin/configuration/configure-ktlint.gradle.kts +++ b/build-config/src/main/kotlin/configuration/configure-ktlint.gradle.kts @@ -6,5 +6,4 @@ configure { val libs = extensions.getByType().named("libs") version = libs.findVersion("ktlint").get().toString() - disabledRules = setOf("filename") } diff --git a/gradle.properties b/gradle.properties index 91bf78ea..3cf16b7c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,6 @@ android.library.defaults.buildfeatures.androidresources=false # Kotlin kotlin.code.style=official -kotlin.native.useEmbeddableCompilerJar=true kotlin.native.ignoreDisabledTargets=true kotlin.mpp.stability.nowarn=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93fb631a..ef25c809 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,23 +1,22 @@ [versions] -agp = "8.11.0" -kotlin = "2.2.0" +agp = "8.12.2" +kotlin = "2.2.21" mavenPublish = "0.33.0" -composeMultiplatform = "1.8.2" -binaryCompatibilityValidator = "0.18.0" +composeMultiplatform = "1.10.3" +binaryCompatibilityValidator = "0.18.1" atomicfu = "0.29.0" -ktlint = "0.47.1" -ktlintPlugin = "12.3.0" +ktlint = "1.0.1" +ktlintPlugin = "13.0.0" coroutines = "1.10.2" -kodein = "7.21.2" -koin-compose = "4.1.0" +kodein = "7.29.0" +koin-compose = "4.1.1" hilt = "2.56.2" -lifecycle = "2.9.1" -activityCompose = "1.10.1" -rxjava = "3.1.10" +lifecycle = "2.10.0" +activityCompose = "1.12.0" +rxjava = "3.1.12" -androidxKmp-bundle = "1.0.1" -androidxKmp-lifecycle = "2.9.1" +androidxKmp-lifecycle = "2.10.0" junit = "5.13.2" @@ -41,10 +40,14 @@ androidx-lifecycle-livedata = { module = "androidx.lifecycle:lifecycle-livedata- androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" } rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" } -androidxKmp-core-bundle = { module = "org.jetbrains.androidx.core:core-bundle", version.ref = "androidxKmp-bundle" } +androidxKmp-animation = { module = "org.jetbrains.compose.animation:animation", version.ref = "composeMultiplatform" } androidxKmp-lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidxKmp-lifecycle" } androidxKmp-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "androidxKmp-lifecycle" } androidxKmp-lifecycle-viewmodelCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidxKmp-lifecycle" } +androidxKmp-material = { module = "org.jetbrains.compose.material:material", version.ref = "composeMultiplatform" } +androidxKmp-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeMultiplatform" } +androidxKmp-runtime-saveable = { module = "org.jetbrains.compose.runtime:runtime-saveable", version.ref = "composeMultiplatform" } +androidxKmp-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "composeMultiplatform" } junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } diff --git a/samples/android/build.gradle.kts b/samples/android/build.gradle.kts index f6e171b1..d24ebeec 100644 --- a/samples/android/build.gradle.kts +++ b/samples/android/build.gradle.kts @@ -12,6 +12,7 @@ android { namespace = "cafe.adriel.voyager.sample" defaultConfig { applicationId = "cafe.adriel.voyager.sample" + minSdk = 23 } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/App.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/App.kt index 37214dcf..7378b970 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/App.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/App.kt @@ -46,7 +46,7 @@ class App : Application(), DIAware { viewModel { parameters -> AndroidDetailsViewModel(index = parameters.get()) } - } + }, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleActivity.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleActivity.kt index 7ecbf302..c2680073 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleActivity.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleActivity.kt @@ -50,7 +50,7 @@ class SampleActivity : ComponentActivity() { verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(24.dp) + contentPadding = PaddingValues(24.dp), ) { item { StartSampleButton("SnapshotStateStack") @@ -78,7 +78,7 @@ class SampleActivity : ComponentActivity() { Button( onClick = { context.startActivity(Intent(this, T::class.java)) }, - modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp) + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), ) { Text(text = text) } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleContent.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleContent.kt index 87a3609b..afd6ca2d 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleContent.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/SampleContent.kt @@ -28,7 +28,7 @@ val sampleItems: List fun LoadingContent() { Box( contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { CircularProgressIndicator() } @@ -41,7 +41,7 @@ fun ListContent(items: List, onClick: ((Int) -> Unit)? = null) { itemsIndexed(items) { index, item -> ListItem( text = { Text(text = item) }, - modifier = if (onClick == null) Modifier else Modifier.clickable { onClick(index) } + modifier = if (onClick == null) Modifier else Modifier.clickable { onClick(index) }, ) } } @@ -52,25 +52,25 @@ fun DetailsContent(instance: Any, item: String, onClick: () -> Unit) { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { Text( text = item, - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(16.dp)) Text( text = instance.toString().substringAfterLast('.'), - style = MaterialTheme.typography.body2 + style = MaterialTheme.typography.body2, ) Spacer(modifier = Modifier.height(16.dp)) Button( onClick = onClick, - content = { Text(text = "Back") } + content = { Text(text = "Back") }, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenOne.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenOne.kt index 63bff5e0..87a1e4cd 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenOne.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenOne.kt @@ -30,25 +30,25 @@ class LegacyScreenOne : Screen { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { Text( text = model.text, - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(16.dp)) Text( text = model.toString().substringAfterLast('.'), - style = MaterialTheme.typography.body2 + style = MaterialTheme.typography.body2, ) Spacer(modifier = Modifier.height(16.dp)) Button( onClick = { navigator.push(LegacyScreenTwo()) }, - content = { Text(text = "Go to Two") } + content = { Text(text = "Go to Two") }, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenTwo.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenTwo.kt index deceb287..a07edb02 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenTwo.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidLegacy/LegacyScreenTwo.kt @@ -30,25 +30,25 @@ class LegacyScreenTwo : Screen { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { Text( text = model.text, - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(16.dp)) Text( text = model.toString().substringAfterLast('.'), - style = MaterialTheme.typography.body2 + style = MaterialTheme.typography.body2, ) Spacer(modifier = Modifier.height(16.dp)) Button( onClick = navigator::pop, - content = { Text(text = "Go to One") } + content = { Text(text = "Go to One") }, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsScreen.kt index 8412a03a..ce082543 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsScreen.kt @@ -11,7 +11,7 @@ import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf data class AndroidDetailsScreen( - val index: Int + val index: Int, ) : Screen { override val key: ScreenKey = uniqueScreenKey diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsViewModel.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsViewModel.kt index 7fc08d34..e2871f51 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsViewModel.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/androidViewModel/AndroidDetailsViewModel.kt @@ -3,7 +3,7 @@ package cafe.adriel.voyager.sample.androidViewModel import androidx.lifecycle.ViewModel class AndroidDetailsViewModel( - val index: Int + val index: Int, ) : ViewModel() { override fun onCleared() { diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationActivity.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationActivity.kt index babfc127..2de2e246 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationActivity.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationActivity.kt @@ -17,7 +17,7 @@ class BasicNavigationActivity : ComponentActivity() { onBackPressed = { currentScreen -> Log.d("Navigator", "Pop screen #${(currentScreen as BasicNavigationScreen).index}") true - } + }, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt index b9a490ac..b7a2f932 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt @@ -26,7 +26,7 @@ import cafe.adriel.voyager.navigator.currentOrThrow data class BasicNavigationScreen( val index: Int, - val wrapContent: Boolean = false + val wrapContent: Boolean = false, ) : Screen { override val key = uniqueScreenKey @@ -57,22 +57,22 @@ data class BasicNavigationScreen( } else { fillMaxSize() } - } + }, ) { Text( text = "Screen #$index", - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(24.dp)) Row( - modifier = Modifier.padding(16.dp) + modifier = Modifier.padding(16.dp), ) { Button( enabled = navigator.canPop, onClick = navigator::pop, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Pop") } @@ -81,7 +81,7 @@ data class BasicNavigationScreen( Button( onClick = { navigator.push(BasicNavigationScreen(index.inc(), wrapContent)) }, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Push") } @@ -90,14 +90,14 @@ data class BasicNavigationScreen( Button( onClick = { navigator.replace(BasicNavigationScreen(index.inc(), wrapContent)) }, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Replace") } } LazyColumn( - modifier = Modifier.height(100.dp) + modifier = Modifier.height(100.dp), ) { items(100) { Text("Item #$it") diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/bottomSheetNavigation/BackScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/bottomSheetNavigation/BackScreen.kt index 041dce87..7d2f86f2 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/bottomSheetNavigation/BackScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/bottomSheetNavigation/BackScreen.kt @@ -19,10 +19,10 @@ class BackScreen : Screen { Box( contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { Button( - onClick = { bottomSheetNavigator.show(BasicNavigationScreen(index = 0, wrapContent = true)) } + onClick = { bottomSheetNavigator.show(BasicNavigationScreen(index = 0, wrapContent = true)) }, ) { Text(text = "Show BottomSheet") } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreen.kt index 83f2559c..1380267f 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreen.kt @@ -10,7 +10,7 @@ import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.sample.DetailsContent data class HiltDetailsScreen( - val index: Int + val index: Int, ) : Screen { override val key: ScreenKey = uniqueScreenKey diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreenModel.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreenModel.kt index 2bb80721..63a47950 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreenModel.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsScreenModel.kt @@ -8,7 +8,7 @@ import dagger.assisted.AssistedInject // Working with Assisted Injection here to simulate a custom param in the constructor class HiltDetailsScreenModel @AssistedInject constructor( - @Assisted val index: Int + @Assisted val index: Int, ) : ScreenModel { @AssistedFactory diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsViewModel.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsViewModel.kt index 8546b01e..3a26c611 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsViewModel.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltDetailsViewModel.kt @@ -8,7 +8,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel @HiltViewModel(assistedFactory = HiltDetailsViewModel.Factory::class) class HiltDetailsViewModel @AssistedInject constructor( - @Assisted val index: Int + @Assisted val index: Int, ) : ViewModel() { @AssistedFactory diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltListViewModel.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltListViewModel.kt index ebeb971d..1d26985a 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltListViewModel.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltListViewModel.kt @@ -8,7 +8,7 @@ import javax.inject.Inject @HiltViewModel class HiltListViewModel @Inject constructor( - private val handle: SavedStateHandle + private val handle: SavedStateHandle, ) : ViewModel() { init { diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltModule.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltModule.kt index 7cd7011c..45b6c60f 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltModule.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/hiltIntegration/HiltModule.kt @@ -22,6 +22,6 @@ abstract class HiltModule { @IntoMap @ScreenModelFactoryKey(HiltDetailsScreenModel.Factory::class) abstract fun bindHiltDetailsScreenModelFactory( - hiltDetailsScreenModelFactory: HiltDetailsScreenModel.Factory + hiltDetailsScreenModelFactory: HiltDetailsScreenModel.Factory, ): ScreenModelFactory } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/kodeinIntegration/KodeinScopedDependencySample.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/kodeinIntegration/KodeinScopedDependencySample.kt index 48638b48..b6591d38 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/kodeinIntegration/KodeinScopedDependencySample.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/kodeinIntegration/KodeinScopedDependencySample.kt @@ -3,7 +3,7 @@ package cafe.adriel.voyager.sample.kodeinIntegration import org.kodein.di.bindings.ScopeCloseable data class KodeinScopedDependencySample( - val screenKey: String + val screenKey: String, ) : ScopeCloseable { override fun close() { println("Being disposed") diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/liveDataIntegration/LiveDataScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/liveDataIntegration/LiveDataScreen.kt index ead1a7ea..66d693ac 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/liveDataIntegration/LiveDataScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/liveDataIntegration/LiveDataScreen.kt @@ -2,7 +2,7 @@ package cafe.adriel.voyager.sample.liveDataIntegration import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.currentCompositeKeyHash +import androidx.compose.runtime.currentCompositeKeyHashCode import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import cafe.adriel.voyager.core.model.rememberScreenModel @@ -27,7 +27,7 @@ class LiveDataScreen : Screen { else -> Unit } - LaunchedEffect(currentCompositeKeyHash) { + LaunchedEffect(currentCompositeKeyHashCode) { screenModel.getItems() } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/nestedNavigation/NestedNavigationActivity.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/nestedNavigation/NestedNavigationActivity.kt index d8f22a22..c6f0c743 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/nestedNavigation/NestedNavigationActivity.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/nestedNavigation/NestedNavigationActivity.kt @@ -43,7 +43,7 @@ class NestedNavigationActivity : ComponentActivity() { CurrentScreen() Button( onClick = { navigator.popUntilRoot() }, - modifier = Modifier.padding(bottom = 16.dp) + modifier = Modifier.padding(bottom = 16.dp), ) { Text(text = "Pop Until Root") } @@ -53,22 +53,19 @@ class NestedNavigationActivity : ComponentActivity() { } @Composable - private fun NestedNavigation( - backgroundColor: Color, - content: NavigatorContent = { CurrentScreen() } - ) { + private fun NestedNavigation(backgroundColor: Color, content: NavigatorContent = { CurrentScreen() }) { Navigator( - screen = BasicNavigationScreen(index = 0, wrapContent = true) + screen = BasicNavigationScreen(index = 0, wrapContent = true), ) { navigator -> Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier .padding(16.dp) - .background(backgroundColor) + .background(backgroundColor), ) { Text( text = "Level #${navigator.level}", - modifier = Modifier.padding(8.dp) + modifier = Modifier.padding(8.dp), ) content(navigator) } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/ParcelableActivity.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/ParcelableActivity.kt index 91ff5c87..0d270cc7 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/ParcelableActivity.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/ParcelableActivity.kt @@ -17,7 +17,7 @@ class ParcelableActivity : ComponentActivity() { onBackPressed = { currentScreen -> Log.d("Navigator", "Pop screen #${(currentScreen as SampleParcelableScreen).parcelable.index}") true - } + }, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/SampleParcelableScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/SampleParcelableScreen.kt index c8212050..0ef4de8c 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/SampleParcelableScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/parcelableScreen/SampleParcelableScreen.kt @@ -28,13 +28,13 @@ import kotlinx.parcelize.Parcelize @Parcelize data class ParcelableContent( - val index: Int + val index: Int, ) : Parcelable @Parcelize data class SampleParcelableScreen( val parcelable: ParcelableContent, - val wrapContent: Boolean = false + val wrapContent: Boolean = false, ) : Screen, Parcelable { @IgnoredOnParcel @@ -60,22 +60,22 @@ data class SampleParcelableScreen( } else { fillMaxSize() } - } + }, ) { Text( text = "Screen #${parcelable.index}", - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(24.dp)) Row( - modifier = Modifier.padding(16.dp) + modifier = Modifier.padding(16.dp), ) { Button( enabled = navigator.canPop, onClick = navigator::pop, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Pop") } @@ -85,10 +85,10 @@ data class SampleParcelableScreen( Button( onClick = { navigator.push( - SampleParcelableScreen(parcelable.copy(index = parcelable.index.inc()), wrapContent) + SampleParcelableScreen(parcelable.copy(index = parcelable.index.inc()), wrapContent), ) }, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Push") } @@ -98,17 +98,17 @@ data class SampleParcelableScreen( Button( onClick = { navigator.replace( - SampleParcelableScreen(parcelable.copy(index = parcelable.index.inc()), wrapContent) + SampleParcelableScreen(parcelable.copy(index = parcelable.index.inc()), wrapContent), ) }, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Replace") } } LazyColumn( - modifier = Modifier.height(100.dp) + modifier = Modifier.height(100.dp), ) { items(100) { Text("Item #$it") diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/rxjavaIntegration/RxJavaScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/rxjavaIntegration/RxJavaScreen.kt index 4b450013..195a7870 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/rxjavaIntegration/RxJavaScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/rxjavaIntegration/RxJavaScreen.kt @@ -2,7 +2,7 @@ package cafe.adriel.voyager.sample.rxJavaIntegration import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.currentCompositeKeyHash +import androidx.compose.runtime.currentCompositeKeyHashCode import androidx.compose.runtime.getValue import androidx.compose.runtime.rxjava3.subscribeAsState import cafe.adriel.voyager.core.model.rememberScreenModel @@ -26,7 +26,7 @@ class RxJavaScreen : Screen { is RxJavaScreenModel.State.Result -> ListContent(result.items) } - LaunchedEffect(currentCompositeKeyHash) { + LaunchedEffect(currentCompositeKeyHashCode) { screenModel.getItems() } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreen.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreen.kt index 1529a679..00aae63a 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreen.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreen.kt @@ -3,7 +3,7 @@ package cafe.adriel.voyager.sample.screenModel import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.currentCompositeKeyHash +import androidx.compose.runtime.currentCompositeKeyHashCode import androidx.compose.runtime.getValue import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.core.screen.Screen @@ -15,7 +15,7 @@ import cafe.adriel.voyager.sample.DetailsContent import cafe.adriel.voyager.sample.LoadingContent data class DetailsScreen( - val index: Int + val index: Int, ) : Screen { override val key: ScreenKey = uniqueScreenKey @@ -31,7 +31,7 @@ data class DetailsScreen( is DetailsScreenModel.State.Result -> DetailsContent(screenModel, result.item, navigator::pop) } - LaunchedEffect(currentCompositeKeyHash) { + LaunchedEffect(currentCompositeKeyHashCode) { screenModel.getItem(index) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreenModel.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreenModel.kt index 3e31e1e5..92aeb5fb 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreenModel.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenModel/DetailsScreenModel.kt @@ -6,7 +6,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch class DetailsScreenModel( - val index: Int + val index: Int, ) : StateScreenModel(State.Loading) { sealed class State { diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/SampleScreens.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/SampleScreens.kt index 7ca887dc..7d56606c 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/SampleScreens.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/SampleScreens.kt @@ -27,11 +27,11 @@ private val colors = listOf( Color.Yellow, Color.Green, Color.Blue, - Color.Black + Color.Black, ) class BaseSampleScreenModel( - val index: Int + val index: Int, ) : ScreenModel { init { @@ -43,7 +43,7 @@ class BaseSampleScreenModel( } abstract class BaseSampleScreen( - private val transitionType: String + private val transitionType: String, ) : Screen { abstract val index: Int @@ -68,19 +68,19 @@ abstract class BaseSampleScreen( .background(color) .padding(40.dp), verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, ) { Text( text = "Screen $index", fontSize = 24.sp, fontWeight = FontWeight.Bold, - color = contentColor + color = contentColor, ) Spacer(modifier = Modifier.height(8.dp)) Text( text = transitionType, fontSize = 18.sp, - color = contentColor + color = contentColor, ) } } @@ -91,13 +91,13 @@ private fun Color.average(): Color { } data class NoCustomAnimationSampleScreen( - override val index: Int + override val index: Int, ) : BaseSampleScreen("Default transition") data class FadeAnimationSampleScreen( - override val index: Int + override val index: Int, ) : BaseSampleScreen("Fade transition"), ScreenTransition by FadeTransition() data class SlideInVerticallyAnimationSampleScreen( - override val index: Int + override val index: Int, ) : BaseSampleScreen("slide in vertically transition"), ScreenTransition by SlideInVerticallyTransition(index) diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/ScreenTransitionActivity.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/ScreenTransitionActivity.kt index 9f308b9a..aeb5d58c 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/ScreenTransitionActivity.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/screenTransition/ScreenTransitionActivity.kt @@ -35,36 +35,36 @@ class ScreenTransitionActivity : ComponentActivity() { fun Content() { Navigator( screen = NoCustomAnimationSampleScreen(0), - disposeBehavior = NavigatorDisposeBehavior(disposeSteps = false) + disposeBehavior = NavigatorDisposeBehavior(disposeSteps = false), ) { navigator -> Box(modifier = Modifier.fillMaxSize()) { ScreenTransition( navigator = navigator, defaultTransition = SlideTransition(), - disposeScreenAfterTransitionEnd = true + disposeScreenAfterTransitionEnd = true, ) Column( modifier = Modifier .align(Alignment.BottomCenter) - .fillMaxWidth() + .fillMaxWidth(), ) { Row( modifier = Modifier .fillMaxWidth() .padding(10.dp), - horizontalArrangement = Arrangement.spacedBy(20.dp) + horizontalArrangement = Arrangement.spacedBy(20.dp), ) { Button( onClick = { navigator.push(FadeAnimationSampleScreen(navigator.items.size)) }, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) { Text(text = "Fade") } Button( onClick = { navigator.push(SlideInVerticallyAnimationSampleScreen(navigator.items.size)) }, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) { Text(text = "SlideInVertically") } @@ -73,18 +73,18 @@ class ScreenTransitionActivity : ComponentActivity() { modifier = Modifier .fillMaxWidth() .padding(10.dp), - horizontalArrangement = Arrangement.spacedBy(20.dp) + horizontalArrangement = Arrangement.spacedBy(20.dp), ) { Button( onClick = { navigator.push(NoCustomAnimationSampleScreen(navigator.items.size)) }, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) { Text(text = "Default") } Button( onClick = { navigator.pop() }, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) { Text(text = "Pop") } @@ -93,18 +93,18 @@ class ScreenTransitionActivity : ComponentActivity() { modifier = Modifier .fillMaxWidth() .padding(10.dp), - horizontalArrangement = Arrangement.spacedBy(20.dp) + horizontalArrangement = Arrangement.spacedBy(20.dp), ) { Button( onClick = { navigator.replace(NoCustomAnimationSampleScreen(Random.nextInt())) }, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) { Text(text = "Replace") } Button( onClick = { navigator.replaceAll(NoCustomAnimationSampleScreen(Random.nextInt())) }, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) { Text(text = "ReplaceAll") } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/stateStack/StateStackActivity.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/stateStack/StateStackActivity.kt index ee4e355b..a6eb3149 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/stateStack/StateStackActivity.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/stateStack/StateStackActivity.kt @@ -52,7 +52,7 @@ class StateStackActivity : ComponentActivity() { LazyColumn( contentPadding = PaddingValues(16.dp), reverseLayout = true, - modifier = Modifier.weight(.8f) + modifier = Modifier.weight(.8f), ) { itemsIndexed(stateStack.items) { index, item -> ListItem( @@ -60,7 +60,7 @@ class StateStackActivity : ComponentActivity() { item = item, isLast = stateStack.lastItemOrNull == item, isSelected = selectedItem == item, - onSelected = selectItem + onSelected = selectItem, ) } if (stateStack.isEmpty) { @@ -71,13 +71,13 @@ class StateStackActivity : ComponentActivity() { color = Color.DarkGray, fontWeight = FontWeight.Normal, fontFamily = FontFamily.Monospace, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), ) } } } Row( - modifier = Modifier.weight(.1f) + modifier = Modifier.weight(.1f), ) { ActionButton(text = "Pop", enabled = stateStack.canPop) { if (stateStack.lastItemOrNull == selectedItem) { @@ -98,7 +98,7 @@ class StateStackActivity : ComponentActivity() { } } Row( - modifier = Modifier.weight(.1f) + modifier = Modifier.weight(.1f), ) { ActionButton(text = "Replace") { stateStack.replace(randomValue) @@ -116,7 +116,7 @@ class StateStackActivity : ComponentActivity() { item: String, isLast: Boolean, isSelected: Boolean, - onSelected: (String) -> Unit + onSelected: (String) -> Unit, ) { val formattedIndex = index.toString().padStart(3, ' ') Text( @@ -124,22 +124,18 @@ class StateStackActivity : ComponentActivity() { color = if (isSelected) Color.Red else Color.Black, fontWeight = if (isLast) FontWeight.Bold else FontWeight.Normal, fontFamily = FontFamily.Monospace, - modifier = Modifier.clickable { onSelected(item) } + modifier = Modifier.clickable { onSelected(item) }, ) } @Composable - private fun RowScope.ActionButton( - text: String, - enabled: Boolean = true, - onClick: () -> Unit - ) { + private fun RowScope.ActionButton(text: String, enabled: Boolean = true, onClick: () -> Unit) { Button( onClick = onClick, enabled = enabled, modifier = Modifier .weight(.1f) - .padding(8.dp) + .padding(8.dp), ) { Text(text = text) } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/TabNavigationActivity.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/TabNavigationActivity.kt index 26e73ad6..10489d21 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/TabNavigationActivity.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/TabNavigationActivity.kt @@ -3,7 +3,9 @@ package cafe.adriel.voyager.sample.tabNavigation import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.padding import androidx.compose.material.BottomNavigation import androidx.compose.material.BottomNavigationItem import androidx.compose.material.Icon @@ -11,6 +13,7 @@ import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import cafe.adriel.voyager.navigator.tab.CurrentTab import cafe.adriel.voyager.navigator.tab.LocalTabNavigator import cafe.adriel.voyager.navigator.tab.Tab @@ -37,18 +40,20 @@ class TabNavigationActivity : ComponentActivity() { tabDisposable = { TabDisposable( navigator = it, - tabs = listOf(HomeTab, FavoritesTab, ProfileTab) + tabs = listOf(HomeTab, FavoritesTab, ProfileTab), ) - } + }, ) { tabNavigator -> Scaffold( topBar = { TopAppBar( - title = { Text(text = tabNavigator.current.options.title) } + title = { Text(text = tabNavigator.current.options.title) }, ) }, - content = { - CurrentTab() + content = { padding -> + Box(modifier = Modifier.padding(padding)) { + CurrentTab() + } }, bottomBar = { BottomNavigation { @@ -56,7 +61,7 @@ class TabNavigationActivity : ComponentActivity() { TabNavigationItem(FavoritesTab) TabNavigationItem(ProfileTab) } - } + }, ) } } @@ -68,7 +73,7 @@ class TabNavigationActivity : ComponentActivity() { BottomNavigationItem( selected = tabNavigator.current.key == tab.key, onClick = { tabNavigator.current = tab }, - icon = { Icon(painter = tab.options.icon!!, contentDescription = tab.options.title) } + icon = { Icon(painter = tab.options.icon!!, contentDescription = tab.options.title) }, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/FavoritesTab.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/FavoritesTab.kt index c8498751..e8a9b028 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/FavoritesTab.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/FavoritesTab.kt @@ -19,7 +19,7 @@ object FavoritesTab : Tab { TabOptions( index = 1u, title = "Favorites", - icon = icon + icon = icon, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/HomeTab.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/HomeTab.kt index 783c4de1..e7d0ae30 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/HomeTab.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/HomeTab.kt @@ -19,7 +19,7 @@ object HomeTab : Tab { TabOptions( index = 0u, title = "Home", - icon = icon + icon = icon, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/ProfileTab.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/ProfileTab.kt index 19d25c4f..da39340a 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/ProfileTab.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/ProfileTab.kt @@ -19,7 +19,7 @@ object ProfileTab : Tab { TabOptions( index = 2u, title = "Profile", - icon = icon + icon = icon, ) } } diff --git a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt index ffd48d20..4a6bbdcc 100644 --- a/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt +++ b/samples/android/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt @@ -45,7 +45,7 @@ fun Tab.TabContent() { @Composable private fun InnerTabNavigation() { Row( - modifier = Modifier.padding(16.dp) + modifier = Modifier.padding(16.dp), ) { TabNavigationButton(HomeTab) @@ -60,15 +60,13 @@ private fun InnerTabNavigation() { } @Composable -private fun RowScope.TabNavigationButton( - tab: Tab -) { +private fun RowScope.TabNavigationButton(tab: Tab) { val tabNavigator = LocalTabNavigator.current Button( enabled = tabNavigator.current.key != tab.key, onClick = { tabNavigator.current = tab }, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), ) { Text(text = tab.options.title) } diff --git a/samples/multi-module/app/build.gradle.kts b/samples/multi-module/app/build.gradle.kts index 52f9dc19..536cd3fb 100644 --- a/samples/multi-module/app/build.gradle.kts +++ b/samples/multi-module/app/build.gradle.kts @@ -9,6 +9,7 @@ android { namespace = "cafe.adriel.voyager.sample.multimodule" defaultConfig { applicationId = "cafe.adriel.voyager.sample.multimodule" + minSdk = 23 } } diff --git a/samples/multi-module/feature-home/src/main/java/cafe/adriel/voyager/sample/multimodule/home/HomeScreen.kt b/samples/multi-module/feature-home/src/main/java/cafe/adriel/voyager/sample/multimodule/home/HomeScreen.kt index 52d5a82b..8b36ba64 100644 --- a/samples/multi-module/feature-home/src/main/java/cafe/adriel/voyager/sample/multimodule/home/HomeScreen.kt +++ b/samples/multi-module/feature-home/src/main/java/cafe/adriel/voyager/sample/multimodule/home/HomeScreen.kt @@ -33,32 +33,32 @@ class HomeScreen : Screen { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { Text( text = "Home", - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(16.dp)) Button( - onClick = { navigator.push(postListScreen) } + onClick = { navigator.push(postListScreen) }, ) { Text( text = "To Post List", - style = MaterialTheme.typography.button + style = MaterialTheme.typography.button, ) } Spacer(modifier = Modifier.height(16.dp)) Button( - onClick = { navigator.push(postDetailsScreen) } + onClick = { navigator.push(postDetailsScreen) }, ) { Text( text = "To Post Details", - style = MaterialTheme.typography.button + style = MaterialTheme.typography.button, ) } } diff --git a/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/DetailsScreen.kt b/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/DetailsScreen.kt index 8081006a..a533d2e1 100644 --- a/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/DetailsScreen.kt +++ b/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/DetailsScreen.kt @@ -17,7 +17,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow data class DetailsScreen( - val id: String + val id: String, ) : Screen { @Composable @@ -27,28 +27,28 @@ data class DetailsScreen( Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { Text( text = "Post Details", - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(16.dp)) Text( text = "ID: $id", - style = MaterialTheme.typography.body1 + style = MaterialTheme.typography.body1, ) Spacer(modifier = Modifier.height(16.dp)) Button( - onClick = { navigator.pop() } + onClick = { navigator.pop() }, ) { Text( text = "Return", - style = MaterialTheme.typography.button + style = MaterialTheme.typography.button, ) } } diff --git a/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/ListScreen.kt b/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/ListScreen.kt index 7f7baa9a..28dfd9f9 100644 --- a/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/ListScreen.kt +++ b/samples/multi-module/feature-posts/src/main/java/cafe/adriel/voyager/sample/multimodule/posts/ListScreen.kt @@ -25,21 +25,21 @@ class ListScreen : Screen { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { Text( text = "Post List", - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(16.dp)) Button( - onClick = { navigator.pop() } + onClick = { navigator.pop() }, ) { Text( text = "Return", - style = MaterialTheme.typography.button + style = MaterialTheme.typography.button, ) } } diff --git a/samples/multiplatform-iosApp/iosApp/ContentView.swift b/samples/multiplatform-iosApp/iosApp/ContentView.swift index 3cd5c325..a878f102 100644 --- a/samples/multiplatform-iosApp/iosApp/ContentView.swift +++ b/samples/multiplatform-iosApp/iosApp/ContentView.swift @@ -4,7 +4,7 @@ import ComposeApp struct ComposeView: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController { - MainViewControllerKt.MainViewController() + MainViewControllerKt.mainViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} diff --git a/samples/multiplatform/build.gradle.kts b/samples/multiplatform/build.gradle.kts index 990bcacd..390592c3 100644 --- a/samples/multiplatform/build.gradle.kts +++ b/samples/multiplatform/build.gradle.kts @@ -17,6 +17,7 @@ android { namespace = "cafe.adriel.voyager.sample.multiplatform" defaultConfig { applicationId = "cafe.adriel.voyager.sample.multiplatform" + minSdk = 23 } } @@ -25,7 +26,7 @@ kotlin { listOf( macosX64(), - macosArm64() + macosArm64(), ).forEach { macosTarget -> macosTarget.binaries { executable { @@ -34,7 +35,7 @@ kotlin { "-linker-option", "-framework", "-linker-option", - "Metal" + "Metal", ) } } @@ -43,7 +44,7 @@ kotlin { listOf( iosX64(), iosArm64(), - iosSimulatorArm64() + iosSimulatorArm64(), ).forEach { iosTarget -> iosTarget.binaries.framework { baseName = "ComposeApp" @@ -83,9 +84,9 @@ kotlin { implementation(projects.voyagerCore) implementation(projects.voyagerNavigator) implementation(projects.voyagerTransitions) - implementation(compose.runtime) - implementation(compose.ui) - implementation(compose.material) + implementation(libs.androidxKmp.runtime) + implementation(libs.androidxKmp.ui) + implementation(libs.androidxKmp.material) implementation(libs.coroutines.core) } androidMain.dependencies { diff --git a/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/Application.kt b/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/Application.kt index c23c9364..e1748afc 100644 --- a/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/Application.kt +++ b/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/Application.kt @@ -11,7 +11,7 @@ public fun SampleApplication() { onBackPressed = { currentScreen -> println("Navigator: Pop screen #${(currentScreen as BasicNavigationScreen).index}") true - } + }, ) { navigator -> SlideTransition(navigator) } diff --git a/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/BasicNavigationScreen.kt b/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/BasicNavigationScreen.kt index df93500a..8ad7ca81 100644 --- a/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/BasicNavigationScreen.kt +++ b/samples/multiplatform/src/commonMain/kotlin/cafe/adriel/voyager/sample/multiplatform/BasicNavigationScreen.kt @@ -25,7 +25,7 @@ import cafe.adriel.voyager.navigator.currentOrThrow public data class BasicNavigationScreen( val index: Int, - val wrapContent: Boolean = false + val wrapContent: Boolean = false, ) : Screen { override val key: ScreenKey = uniqueScreenKey @@ -50,22 +50,22 @@ public data class BasicNavigationScreen( } else { fillMaxSize() } - } + }, ) { Text( text = "Screen #$index", - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.h5, ) Spacer(modifier = Modifier.height(24.dp)) Row( - modifier = Modifier.padding(16.dp) + modifier = Modifier.padding(16.dp), ) { Button( enabled = navigator.canPop, onClick = navigator::pop, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Pop") } @@ -74,7 +74,7 @@ public data class BasicNavigationScreen( Button( onClick = { navigator.push(BasicNavigationScreen(index.inc(), wrapContent)) }, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Push") } @@ -83,14 +83,14 @@ public data class BasicNavigationScreen( Button( onClick = { navigator.replace(BasicNavigationScreen(index.inc(), wrapContent)) }, - modifier = Modifier.weight(.5f) + modifier = Modifier.weight(.5f), ) { Text(text = "Replace") } } LazyColumn( - modifier = Modifier.height(100.dp) + modifier = Modifier.height(100.dp), ) { items(100) { Text("Item #$it") diff --git a/samples/multiplatform/src/iosMain/kotlin/MainViewController.kt b/samples/multiplatform/src/iosMain/kotlin/MainViewController.kt index dee0b397..0d337128 100644 --- a/samples/multiplatform/src/iosMain/kotlin/MainViewController.kt +++ b/samples/multiplatform/src/iosMain/kotlin/MainViewController.kt @@ -1,4 +1,4 @@ import androidx.compose.ui.window.ComposeUIViewController import cafe.adriel.voyager.sample.multiplatform.SampleApplication -fun MainViewController() = ComposeUIViewController { SampleApplication() } +fun mainViewController() = ComposeUIViewController { SampleApplication() } diff --git a/voyager-bottom-sheet-navigator/build.gradle.kts b/voyager-bottom-sheet-navigator/build.gradle.kts index cf0e0e89..2d6f2957 100644 --- a/voyager-bottom-sheet-navigator/build.gradle.kts +++ b/voyager-bottom-sheet-navigator/build.gradle.kts @@ -15,8 +15,8 @@ kotlin { commonMain.dependencies { api(projects.voyagerCore) api(projects.voyagerNavigator) - implementation(compose.runtime) - implementation(compose.material) + implementation(libs.androidxKmp.runtime) + implementation(libs.androidxKmp.material) } androidMain.dependencies { implementation(libs.androidx.activity.compose) diff --git a/voyager-bottom-sheet-navigator/src/androidMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.kt b/voyager-bottom-sheet-navigator/src/androidMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.kt index ddbc8be4..698bc698 100644 --- a/voyager-bottom-sheet-navigator/src/androidMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.kt +++ b/voyager-bottom-sheet-navigator/src/androidMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.kt @@ -4,5 +4,4 @@ import androidx.activity.compose.BackHandler import androidx.compose.runtime.Composable @Composable -internal actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) = - BackHandler(enabled, onBack) +internal actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) = BackHandler(enabled, onBack) diff --git a/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/BottomSheetNavigator.kt b/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/BottomSheetNavigator.kt index 5a93ef94..d6e91d67 100644 --- a/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/BottomSheetNavigator.kt +++ b/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/BottomSheetNavigator.kt @@ -53,14 +53,14 @@ public fun BottomSheetNavigator( animationSpec: AnimationSpec = ModalBottomSheetDefaults.AnimationSpec, key: String = compositionUniqueId(), sheetContent: BottomSheetNavigatorContent = { CurrentScreen() }, - content: BottomSheetNavigatorContent + content: BottomSheetNavigatorContent, ) { var hideBottomSheet: (() -> Unit)? = null val coroutineScope = rememberCoroutineScope() val sheetState = rememberModalBottomSheetState( initialValue = ModalBottomSheetValue.Hidden, skipHalfExpanded = skipHalfExpanded, - animationSpec = animationSpec + animationSpec = animationSpec, ) LaunchedEffect(sheetState, sheetState.currentValue) { @@ -92,7 +92,7 @@ public fun BottomSheetNavigator( }, content = { content(bottomSheetNavigator) - } + }, ) } } @@ -102,9 +102,8 @@ public fun BottomSheetNavigator( public class BottomSheetNavigator @InternalVoyagerApi constructor( private val navigator: Navigator, private val sheetState: ModalBottomSheetState, - private val coroutineScope: CoroutineScope + private val coroutineScope: CoroutineScope, ) : Stack by navigator { - public val isVisible: Boolean get() = sheetState.isVisible @@ -128,16 +127,12 @@ public class BottomSheetNavigator @InternalVoyagerApi constructor( } @Composable - public fun saveableState( - key: String, - content: @Composable () -> Unit - ) { + public fun saveableState(key: String, content: @Composable () -> Unit) { navigator.saveableState(key, content = content) } } private object HiddenBottomSheetScreen : Screen { - @Composable override fun Content() { Spacer(modifier = Modifier.height(1.dp)) diff --git a/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/BottomSheetNavigatorBackHandler.kt b/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/BottomSheetNavigatorBackHandler.kt index bdb13b89..8211a85a 100644 --- a/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/BottomSheetNavigatorBackHandler.kt +++ b/voyager-bottom-sheet-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/BottomSheetNavigatorBackHandler.kt @@ -13,7 +13,7 @@ internal expect fun BackHandler(enabled: Boolean, onBack: () -> Unit) internal fun BottomSheetNavigatorBackHandler( navigator: BottomSheetNavigator, sheetState: ModalBottomSheetState, - hideOnBackPress: Boolean + hideOnBackPress: Boolean, ) { BackHandler(enabled = sheetState.isVisible) { if (navigator.pop().not() && hideOnBackPress) { diff --git a/voyager-core/build.gradle.kts b/voyager-core/build.gradle.kts index 53dce871..0e194d52 100644 --- a/voyager-core/build.gradle.kts +++ b/voyager-core/build.gradle.kts @@ -14,8 +14,8 @@ android { kotlin { sourceSets { commonMain.dependencies { - implementation(compose.runtime) - implementation(compose.runtimeSaveable) + implementation(libs.androidxKmp.runtime) + implementation(libs.androidxKmp.runtime.saveable) implementation(libs.coroutines.core) } commonJvmTest.dependencies { diff --git a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt index bf21ef26..7eab3cc8 100644 --- a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt +++ b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt @@ -45,7 +45,6 @@ public class AndroidScreenLifecycleOwner private constructor() : ViewModelStoreOwner, SavedStateRegistryOwner, HasDefaultViewModelProviderFactory { - override val lifecycle: LifecycleRegistry = LifecycleRegistry(this) override val viewModelStore: ViewModelStore = ViewModelStore() @@ -61,24 +60,26 @@ public class AndroidScreenLifecycleOwner private constructor() : get() = controller.savedStateRegistry override val defaultViewModelProviderFactory: ViewModelProvider.Factory - get() = SavedStateViewModelFactory( - application = atomicAppContext.get()?.getApplication(), - owner = this - ) + get() = + SavedStateViewModelFactory( + application = atomicAppContext.get()?.getApplication(), + owner = this, + ) override val defaultViewModelCreationExtras: CreationExtras - get() = MutableCreationExtras().apply { - val application = atomicAppContext.get()?.getApplication() - if (application != null) { - set(AndroidViewModelFactory.APPLICATION_KEY, application) - } - set(SAVED_STATE_REGISTRY_OWNER_KEY, this@AndroidScreenLifecycleOwner) - set(VIEW_MODEL_STORE_OWNER_KEY, this@AndroidScreenLifecycleOwner) + get() = + MutableCreationExtras().apply { + val application = atomicAppContext.get()?.getApplication() + if (application != null) { + set(AndroidViewModelFactory.APPLICATION_KEY, application) + } + set(SAVED_STATE_REGISTRY_OWNER_KEY, this@AndroidScreenLifecycleOwner) + set(VIEW_MODEL_STORE_OWNER_KEY, this@AndroidScreenLifecycleOwner) /* TODO if (getArguments() != null) { extras.set(DEFAULT_ARGS_KEY, getArguments()) }*/ - } + } init { controller.performAttach() @@ -109,7 +110,7 @@ public class AndroidScreenLifecycleOwner private constructor() : @Composable override fun ProvideBeforeScreenContent( provideSaveableState: @Composable (suffixKey: String, content: @Composable () -> Unit) -> Unit, - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { provideSaveableState("lifecycle") { LifecycleDisposableEffect() @@ -142,7 +143,7 @@ public class AndroidScreenLifecycleOwner private constructor() : listOf( LocalLifecycleOwner provides this, LocalViewModelStoreOwner provides this, - LocalSavedStateRegistryOwner provides this + LocalSavedStateRegistryOwner provides this, ) } } @@ -153,26 +154,27 @@ public class AndroidScreenLifecycleOwner private constructor() : private fun registerLifecycleListener(outState: Bundle): () -> Unit { val lifecycleOwner = atomicParentLifecycleOwner.get() if (lifecycleOwner != null) { - val observer = object : DefaultLifecycleObserver { - override fun onPause(owner: LifecycleOwner) { - lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_PAUSE) - } - - override fun onResume(owner: LifecycleOwner) { - lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_RESUME) - } - - override fun onStart(owner: LifecycleOwner) { - lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_START) + val observer = + object : DefaultLifecycleObserver { + override fun onPause(owner: LifecycleOwner) { + lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_PAUSE) + } + + override fun onResume(owner: LifecycleOwner) { + lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_RESUME) + } + + override fun onStart(owner: LifecycleOwner) { + lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_START) + } + + override fun onStop(owner: LifecycleOwner) { + lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_STOP) + + // when the Application goes to background, perform save + performSave(outState) + } } - - override fun onStop(owner: LifecycleOwner) { - lifecycle.safeHandleLifecycleEvent(Lifecycle.Event.ON_STOP) - - // when the Application goes to background, perform save - performSave(outState) - } - } val lifecycle = lifecycleOwner.lifecycle lifecycle.addObserver(observer) @@ -218,24 +220,27 @@ public class AndroidScreenLifecycleOwner private constructor() : } public companion object { + private val initEvents = + arrayOf( + Lifecycle.Event.ON_CREATE, + ) - private val initEvents = arrayOf( - Lifecycle.Event.ON_CREATE - ) - - private val startEvents = arrayOf( - Lifecycle.Event.ON_START, - Lifecycle.Event.ON_RESUME - ) + private val startEvents = + arrayOf( + Lifecycle.Event.ON_START, + Lifecycle.Event.ON_RESUME, + ) - private val stopEvents = arrayOf( - Lifecycle.Event.ON_PAUSE, - Lifecycle.Event.ON_STOP - ) + private val stopEvents = + arrayOf( + Lifecycle.Event.ON_PAUSE, + Lifecycle.Event.ON_STOP, + ) - private val disposeEvents = arrayOf( - Lifecycle.Event.ON_DESTROY - ) + private val disposeEvents = + arrayOf( + Lifecycle.Event.ON_DESTROY, + ) public fun get(screen: Screen): ScreenLifecycleOwner { return ScreenLifecycleStore.get(screen) { AndroidScreenLifecycleOwner() } diff --git a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/core/lifecycle/ConfigurationChecker.kt b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/core/lifecycle/ConfigurationChecker.kt index 3ca7c7a5..13ea04d3 100644 --- a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/core/lifecycle/ConfigurationChecker.kt +++ b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/core/lifecycle/ConfigurationChecker.kt @@ -1,25 +1,17 @@ package cafe.adriel.voyager.core.lifecycle import android.app.Activity -import android.content.Context -import android.content.ContextWrapper +import androidx.activity.compose.LocalActivity import androidx.compose.runtime.Composable import androidx.compose.runtime.NonRestartableComposable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext - -private tailrec fun Context.getActivity(): Activity? = when (this) { - is Activity -> this - is ContextWrapper -> baseContext.getActivity() - else -> null -} @Composable @NonRestartableComposable internal actual fun getConfigurationChecker(): ConfigurationChecker { - val context = LocalContext.current - return remember(context) { ConfigurationChecker(context.getActivity()) } + val activity = LocalActivity.current + return remember(activity) { ConfigurationChecker(activity) } } @Stable diff --git a/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/stack/SnapshotStateStackTest.kt b/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/stack/SnapshotStateStackTest.kt index 94fb6c33..32d3b2c7 100644 --- a/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/stack/SnapshotStateStackTest.kt +++ b/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/stack/SnapshotStateStackTest.kt @@ -8,248 +8,233 @@ import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows internal class SnapshotStateStackTest { - @TestFactory - fun initSingle(): Sequence = - sequenceOf( - "item 1" to 0, - "item 1" to 1 - ).map { (item, minSize) -> - dynamicTest("when min size is $minSize then should not throw") { - assertDoesNotThrow { - SnapshotStateStack(item, minSize) - } + fun initSingle(): Sequence = sequenceOf( + "item 1" to 0, + "item 1" to 1, + ).map { (item, minSize) -> + dynamicTest("when min size is $minSize then should not throw") { + assertDoesNotThrow { + SnapshotStateStack(item, minSize) } } + } @TestFactory - fun initList(): Sequence = - sequenceOf( - Triple(emptyList(), 0, false), - Triple(emptyList(), 1, true), - Triple(listOf("item 1"), 0, false), - Triple(listOf("item 1"), 1, false), - Triple(listOf("item 1", "item 2"), 0, false), - Triple(listOf("item 1", "item 2"), 1, false) - ).map { (items, minSize, throws) -> - dynamicTest( - "when items size is ${items.size} and min size is $minSize " + - "then should ${if (throws) "" else "not"} throw" - ) { - if (throws) { - assertThrows { - SnapshotStateStack(items, minSize) - } - } else { - assertDoesNotThrow { - SnapshotStateStack(items, minSize) - } + fun initList(): Sequence = sequenceOf( + Triple(emptyList(), 0, false), + Triple(emptyList(), 1, true), + Triple(listOf("item 1"), 0, false), + Triple(listOf("item 1"), 1, false), + Triple(listOf("item 1", "item 2"), 0, false), + Triple(listOf("item 1", "item 2"), 1, false), + ).map { (items, minSize, throws) -> + dynamicTest( + "when items size is ${items.size} and min size is $minSize " + + "then should ${if (throws) "" else "not"} throw", + ) { + if (throws) { + assertThrows { + SnapshotStateStack(items, minSize) + } + } else { + assertDoesNotThrow { + SnapshotStateStack(items, minSize) } } } + } @TestFactory - fun items(): Sequence = - sequenceOf( - emptyList(), - listOf("item 1"), - listOf("item 1", "item 2") - ).map { items -> - dynamicTest("when items size is ${items.size} then return same content") { - val stack = SnapshotStateStack(items) - - assert(stack.items == items) - } + fun items(): Sequence = sequenceOf( + emptyList(), + listOf("item 1"), + listOf("item 1", "item 2"), + ).map { items -> + dynamicTest("when items size is ${items.size} then return same content") { + val stack = SnapshotStateStack(items) + + assert(stack.items == items) } + } @TestFactory - fun lastOrNull(): Sequence = - sequenceOf( - Triple(emptyList(), null, false), - Triple(listOf("item 1"), "item 1", true), - Triple(listOf("item 1", "item 2"), "item 2", true) - ).map { (items, expected, success) -> - dynamicTest("when items size is ${items.size} then return ${if (success) "last" else "null"}") { - val stack = SnapshotStateStack(items) - - assert(stack.lastItemOrNull == expected) - } + fun lastOrNull(): Sequence = sequenceOf( + Triple(emptyList(), null, false), + Triple(listOf("item 1"), "item 1", true), + Triple(listOf("item 1", "item 2"), "item 2", true), + ).map { (items, expected, success) -> + dynamicTest("when items size is ${items.size} then return ${if (success) "last" else "null"}") { + val stack = SnapshotStateStack(items) + + assert(stack.lastItemOrNull == expected) } + } @TestFactory - fun size(): Sequence = - sequenceOf( - emptyList() to 0, - listOf("item 1") to 1, - listOf("item 1", "item 2") to 2 - ).map { (items, expected) -> - dynamicTest("when items size is ${items.size} then return $expected") { - val stack = SnapshotStateStack(items) - - assert(stack.size == expected) - } + fun size(): Sequence = sequenceOf( + emptyList() to 0, + listOf("item 1") to 1, + listOf("item 1", "item 2") to 2, + ).map { (items, expected) -> + dynamicTest("when items size is ${items.size} then return $expected") { + val stack = SnapshotStateStack(items) + + assert(stack.size == expected) } + } @TestFactory - fun isEmpty(): Sequence = - sequenceOf( - emptyList() to true, - listOf("item 1") to false, - listOf("item 1", "item 2") to false - ).map { (items, expected) -> - dynamicTest("when items size is ${items.size} then return $expected") { - val stack = SnapshotStateStack(items) - - assert(stack.isEmpty == expected) - } + fun isEmpty(): Sequence = sequenceOf( + emptyList() to true, + listOf("item 1") to false, + listOf("item 1", "item 2") to false, + ).map { (items, expected) -> + dynamicTest("when items size is ${items.size} then return $expected") { + val stack = SnapshotStateStack(items) + + assert(stack.isEmpty == expected) } + } @TestFactory - fun canPop(): Sequence = - sequenceOf( - Triple(emptyList(), 0, false), - Triple(listOf("item 1"), 0, true), - Triple(listOf("item 1"), 1, false), - Triple(listOf("item 1", "item 2"), 0, true), - Triple(listOf("item 1", "item 2"), 1, true) - ).map { (items, minSize, expected) -> - dynamicTest("when items size is ${items.size} then return $expected") { - val stack = SnapshotStateStack(items, minSize) - - assert(stack.canPop == expected) - } + fun canPop(): Sequence = sequenceOf( + Triple(emptyList(), 0, false), + Triple(listOf("item 1"), 0, true), + Triple(listOf("item 1"), 1, false), + Triple(listOf("item 1", "item 2"), 0, true), + Triple(listOf("item 1", "item 2"), 1, true), + ).map { (items, minSize, expected) -> + dynamicTest("when items size is ${items.size} then return $expected") { + val stack = SnapshotStateStack(items, minSize) + + assert(stack.canPop == expected) } + } @TestFactory - fun pushSingle(): Sequence = - sequenceOf( - emptyList() to "new item", - listOf("item 1") to "new item", - listOf("item 1", "item 2") to "new item" - ).map { (items, newItem) -> - dynamicTest("when stack size is ${items.size} then last item is new item") { - val stack = SnapshotStateStack(items) - - stack.push(newItem) - - assert(stack.lastItemOrNull == newItem) - } + fun pushSingle(): Sequence = sequenceOf( + emptyList() to "new item", + listOf("item 1") to "new item", + listOf("item 1", "item 2") to "new item", + ).map { (items, newItem) -> + dynamicTest("when stack size is ${items.size} then last item is new item") { + val stack = SnapshotStateStack(items) + + stack.push(newItem) + + assert(stack.lastItemOrNull == newItem) } + } @TestFactory - fun pushList(): Sequence = - sequenceOf( - emptyList() to emptyList(), - listOf("item 1") to listOf("new item"), - listOf("item 1", "item 2") to listOf("new item 1", "new item 2") - ).map { (items, newItems) -> - dynamicTest( - "when stack size is ${items.size} and new items size is ${newItems.size} " + - "then last item is new item" - ) { - val stack = SnapshotStateStack(items) - - stack.push(newItems) - - assert(stack.lastItemOrNull == newItems.lastOrNull()) - } + fun pushList(): Sequence = sequenceOf( + emptyList() to emptyList(), + listOf("item 1") to listOf("new item"), + listOf("item 1", "item 2") to listOf("new item 1", "new item 2"), + ).map { (items, newItems) -> + dynamicTest( + "when stack size is ${items.size} and new items size is ${newItems.size} " + + "then last item is new item", + ) { + val stack = SnapshotStateStack(items) + + stack.push(newItems) + + assert(stack.lastItemOrNull == newItems.lastOrNull()) } + } @TestFactory - fun replace(): Sequence = - sequenceOf( - emptyList() to "new item", - listOf("item 1") to "new item", - listOf("item 1", "item 2") to "new item" - ).map { (items, newItem) -> - dynamicTest("when stack size is ${items.size} then last item is new item") { - val stack = SnapshotStateStack(items) - - stack.replace(newItem) - - assert(stack.lastItemOrNull == newItem) - } + fun replace(): Sequence = sequenceOf( + emptyList() to "new item", + listOf("item 1") to "new item", + listOf("item 1", "item 2") to "new item", + ).map { (items, newItem) -> + dynamicTest("when stack size is ${items.size} then last item is new item") { + val stack = SnapshotStateStack(items) + + stack.replace(newItem) + + assert(stack.lastItemOrNull == newItem) } + } @TestFactory - fun replaceAll(): Sequence = - sequenceOf( - emptyList() to "new item", - listOf("item 1") to "new item", - listOf("item 1", "item 2") to "new item" - ).map { (items, newItem) -> - dynamicTest("when stack size is ${items.size} then last item is new item and size is one") { - val stack = SnapshotStateStack(items) - - stack.replaceAll(newItem) - - assert(stack.size == 1) - assert(stack.lastItemOrNull == newItem) - } + fun replaceAll(): Sequence = sequenceOf( + emptyList() to "new item", + listOf("item 1") to "new item", + listOf("item 1", "item 2") to "new item", + ).map { (items, newItem) -> + dynamicTest("when stack size is ${items.size} then last item is new item and size is one") { + val stack = SnapshotStateStack(items) + + stack.replaceAll(newItem) + + assert(stack.size == 1) + assert(stack.lastItemOrNull == newItem) } + } @TestFactory - fun pop(): Sequence = - sequenceOf( - Quadruple(emptyList(), 0, false, null), - Quadruple(listOf("item 1"), 0, true, null), - Quadruple(listOf("item 1"), 1, false, "item 1"), - Quadruple(listOf("item 1", "item 2"), 0, true, "item 1"), - Quadruple(listOf("item 1", "item 2"), 1, true, "item 1") - ).map { (items, minSize, expected, lastItem) -> - dynamicTest( - "when stack size is ${items.size} and min size is $minSize " + - "then return $expected and last item is $lastItem" - ) { - val stack = SnapshotStateStack(items, minSize) - - assert(stack.pop() == expected) - assert(stack.lastItemOrNull == lastItem) - } + fun pop(): Sequence = sequenceOf( + Quadruple(emptyList(), 0, false, null), + Quadruple(listOf("item 1"), 0, true, null), + Quadruple(listOf("item 1"), 1, false, "item 1"), + Quadruple(listOf("item 1", "item 2"), 0, true, "item 1"), + Quadruple(listOf("item 1", "item 2"), 1, true, "item 1"), + ).map { (items, minSize, expected, lastItem) -> + dynamicTest( + "when stack size is ${items.size} and min size is $minSize " + + "then return $expected and last item is $lastItem", + ) { + val stack = SnapshotStateStack(items, minSize) + + assert(stack.pop() == expected) + assert(stack.lastItemOrNull == lastItem) } + } @TestFactory - fun popAll(): Sequence = - sequenceOf( - Quadruple(emptyList(), 0, 0, null), - Quadruple(listOf("item 1"), 0, 0, null), - Quadruple(listOf("item 1"), 1, 1, "item 1"), - Quadruple(listOf("item 1", "item 2"), 0, 0, null), - Quadruple(listOf("item 1", "item 2"), 1, 1, "item 1") - ).map { (items, minSize, expected, lastItem) -> - dynamicTest( - "when stack size is ${items.size} and min size is $minSize " + - "then size is $expected and last item is $lastItem" - ) { - val stack = SnapshotStateStack(items, minSize) - - stack.popAll() - - assert(stack.size == expected) - assert(stack.lastItemOrNull == lastItem) - } + fun popAll(): Sequence = sequenceOf( + Quadruple(emptyList(), 0, 0, null), + Quadruple(listOf("item 1"), 0, 0, null), + Quadruple(listOf("item 1"), 1, 1, "item 1"), + Quadruple(listOf("item 1", "item 2"), 0, 0, null), + Quadruple(listOf("item 1", "item 2"), 1, 1, "item 1"), + ).map { (items, minSize, expected, lastItem) -> + dynamicTest( + "when stack size is ${items.size} and min size is $minSize " + + "then size is $expected and last item is $lastItem", + ) { + val stack = SnapshotStateStack(items, minSize) + + stack.popAll() + + assert(stack.size == expected) + assert(stack.lastItemOrNull == lastItem) } + } @TestFactory - fun popUntil(): Sequence = - sequenceOf( - Quadruple(emptyList(), 0, null, null), - Quadruple(listOf("item 1"), 0, "item 1", "item 1"), - Quadruple(listOf("item 1"), 1, "item 1", "item 1"), - Quadruple(listOf("item 1", "item 2"), 0, "item 1", "item 1"), - Quadruple(listOf("item 1", "item 2"), 1, "item 1", "item 1"), - Quadruple(listOf("item 1", "item 2"), 0, "item 2", "item 2"), - Quadruple(listOf("item 1", "item 2"), 1, "item 2", "item 2") - ).map { (items, minSize, popItem, lastItem) -> - dynamicTest( - "when stack size is ${items.size}, min size is $minSize and pop until \"$popItem\" " + - "then last item is $lastItem" - ) { - val stack = SnapshotStateStack(items, minSize) - - stack.popUntil { it == popItem } - - assert(stack.lastItemOrNull == lastItem) - } + fun popUntil(): Sequence = sequenceOf( + Quadruple(emptyList(), 0, null, null), + Quadruple(listOf("item 1"), 0, "item 1", "item 1"), + Quadruple(listOf("item 1"), 1, "item 1", "item 1"), + Quadruple(listOf("item 1", "item 2"), 0, "item 1", "item 1"), + Quadruple(listOf("item 1", "item 2"), 1, "item 1", "item 1"), + Quadruple(listOf("item 1", "item 2"), 0, "item 2", "item 2"), + Quadruple(listOf("item 1", "item 2"), 1, "item 2", "item 2"), + ).map { (items, minSize, popItem, lastItem) -> + dynamicTest( + "when stack size is ${items.size}, min size is $minSize and pop until \"$popItem\" " + + "then last item is $lastItem", + ) { + val stack = SnapshotStateStack(items, minSize) + + stack.popUntil { it == popItem } + + assert(stack.lastItemOrNull == lastItem) } + } } diff --git a/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/utils/Quadruple.kt b/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/utils/Quadruple.kt index 21e0145c..ae30b0ce 100644 --- a/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/utils/Quadruple.kt +++ b/voyager-core/src/commonJvmTest/kotlin/cafe/adriel/voyager/core/utils/Quadruple.kt @@ -4,5 +4,5 @@ internal data class Quadruple( val first: A, val second: B, val third: C, - val fourth: D + val fourth: D, ) diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/annotation/InternalVoyagerApi.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/annotation/InternalVoyagerApi.kt index 71e9baba..2def6953 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/annotation/InternalVoyagerApi.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/annotation/InternalVoyagerApi.kt @@ -6,12 +6,12 @@ package cafe.adriel.voyager.core.annotation AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS, - AnnotationTarget.CONSTRUCTOR - ] + AnnotationTarget.CONSTRUCTOR, + ], ) @RequiresOptIn( level = RequiresOptIn.Level.ERROR, - message = "This API is Voyager Internal. It may be changed in the future without notice." + message = "This API is Voyager Internal. It may be changed in the future without notice.", ) public annotation class InternalVoyagerApi @@ -21,11 +21,11 @@ public annotation class InternalVoyagerApi AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS, - AnnotationTarget.CONSTRUCTOR - ] + AnnotationTarget.CONSTRUCTOR, + ], ) @RequiresOptIn( level = RequiresOptIn.Level.ERROR, - message = "This API is experimental. It may be changed in the future without notice." + message = "This API is experimental. It may be changed in the future without notice.", ) public annotation class ExperimentalVoyagerApi diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeList.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeList.kt index f976ece5..02384c4d 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeList.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeList.kt @@ -2,24 +2,44 @@ package cafe.adriel.voyager.core.concurrent public expect class ThreadSafeList() : MutableList { override fun add(element: T): Boolean + override fun add(index: Int, element: T) + override fun addAll(elements: Collection): Boolean + override fun addAll(index: Int, elements: Collection): Boolean + override fun clear() + override fun listIterator(): MutableListIterator + override fun listIterator(index: Int): MutableListIterator + override fun remove(element: T): Boolean + override fun removeAll(elements: Collection): Boolean + override fun removeAt(index: Int): T + override fun retainAll(elements: Collection): Boolean + override fun set(index: Int, element: T): T + override fun subList(fromIndex: Int, toIndex: Int): MutableList + override fun contains(element: T): Boolean + override fun containsAll(elements: Collection): Boolean + override fun get(index: Int): T + override fun indexOf(element: T): Int + override fun isEmpty(): Boolean + override fun iterator(): MutableIterator + override fun lastIndexOf(element: T): Int + override val size: Int } diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeMap.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeMap.kt index c518858b..27626350 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeMap.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeMap.kt @@ -2,15 +2,24 @@ package cafe.adriel.voyager.core.concurrent public expect class ThreadSafeMap() : MutableMap { override fun clear() + override fun put(key: K, value: V): V? + override fun putAll(from: Map) + override fun remove(key: K): V? + override val entries: MutableSet> override val keys: MutableSet override val values: MutableCollection + override fun containsKey(key: K): Boolean + override fun containsValue(value: V): Boolean + override fun get(key: K): V? + override fun isEmpty(): Boolean + override val size: Int } diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeSet.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeSet.kt index 4178525a..92a0fb37 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeSet.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/concurrent/ThreadSafeSet.kt @@ -2,14 +2,24 @@ package cafe.adriel.voyager.core.concurrent public expect class ThreadSafeSet() : MutableSet { override fun add(element: T): Boolean + override fun addAll(elements: Collection): Boolean + override fun clear() + override fun iterator(): MutableIterator + override fun remove(element: T): Boolean + override fun removeAll(elements: Collection): Boolean + override fun retainAll(elements: Collection): Boolean + override fun contains(element: T): Boolean + override fun containsAll(elements: Collection): Boolean + override fun isEmpty(): Boolean + override val size: Int } diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/internal/SafeCollections.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/internal/SafeCollections.kt index c40fc398..a7f817b9 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/internal/SafeCollections.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/internal/SafeCollections.kt @@ -7,8 +7,7 @@ package cafe.adriel.voyager.core.internal internal fun MutableList.removeFirstElement(): T = if (isEmpty()) throw NoSuchElementException("List is empty.") else removeAt(0) -internal fun MutableList.removeFirstElementOrNull(): T? = - if (isEmpty()) null else removeAt(0) +internal fun MutableList.removeFirstElementOrNull(): T? = if (isEmpty()) null else removeAt(0) internal fun MutableList.removeLastElement(): T = if (isEmpty()) throw NoSuchElementException("List is empty.") else removeAt(lastIndex) diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/DisposableEffect.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/DisposableEffect.kt index 74f1bfc9..6d351b7f 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/DisposableEffect.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/DisposableEffect.kt @@ -11,7 +11,7 @@ import androidx.compose.runtime.remember @NonRestartableComposable public fun DisposableEffectIgnoringConfiguration( key1: Any?, - effect: DisposableEffectScope.() -> DisposableEffectResult + effect: DisposableEffectScope.() -> DisposableEffectResult, ) { val configurationChecker = getConfigurationChecker() remember(configurationChecker, key1) { DisposableEffectIgnoringConfigurationImpl(configurationChecker, effect) } @@ -22,7 +22,7 @@ public fun DisposableEffectIgnoringConfiguration( public fun DisposableEffectIgnoringConfiguration( key1: Any?, key2: Any?, - effect: DisposableEffectScope.() -> DisposableEffectResult + effect: DisposableEffectScope.() -> DisposableEffectResult, ) { val configurationChecker = getConfigurationChecker() remember(configurationChecker, key1, key2) { @@ -36,7 +36,7 @@ public fun DisposableEffectIgnoringConfiguration( key1: Any?, key2: Any?, key3: Any?, - effect: DisposableEffectScope.() -> DisposableEffectResult + effect: DisposableEffectScope.() -> DisposableEffectResult, ) { val configurationChecker = getConfigurationChecker() remember(configurationChecker, key1, key2, key3) { @@ -49,7 +49,7 @@ public fun DisposableEffectIgnoringConfiguration( @Suppress("ArrayReturn") public fun DisposableEffectIgnoringConfiguration( vararg keys: Any?, - effect: DisposableEffectScope.() -> DisposableEffectResult + effect: DisposableEffectScope.() -> DisposableEffectResult, ) { val configurationChecker = getConfigurationChecker() remember(configurationChecker, *keys) { DisposableEffectIgnoringConfigurationImpl(configurationChecker, effect) } @@ -59,7 +59,7 @@ private val InternalDisposableEffectScope = DisposableEffectScope() private class DisposableEffectIgnoringConfigurationImpl( private val configurationChecker: ConfigurationChecker, - private val effect: DisposableEffectScope.() -> DisposableEffectResult + private val effect: DisposableEffectScope.() -> DisposableEffectResult, ) : RememberObserver { private var onDispose: DisposableEffectResult? = null diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/multipleScreenLifecycleOwnerUtil.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/MultipleScreenLifecycleOwnerUtil.kt similarity index 90% rename from voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/multipleScreenLifecycleOwnerUtil.kt rename to voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/MultipleScreenLifecycleOwnerUtil.kt index e14e240b..b8e9b841 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/multipleScreenLifecycleOwnerUtil.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/MultipleScreenLifecycleOwnerUtil.kt @@ -11,7 +11,7 @@ import cafe.adriel.voyager.core.internal.removeFirstElementOrNull public fun MultipleProvideBeforeScreenContent( screenLifecycleContentProviders: List, provideSaveableState: @Composable (suffixKey: String, content: @Composable () -> Unit) -> Unit, - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { if (screenLifecycleContentProviders.isNotEmpty()) { val copy = screenLifecycleContentProviders.toMutableList() @@ -19,7 +19,7 @@ public fun MultipleProvideBeforeScreenContent( screenLifecycleContentProvider = copy.removeFirstElement(), provideSaveableState = provideSaveableState, content = content, - nextOrNull = { copy.removeFirstElementOrNull() } + nextOrNull = { copy.removeFirstElementOrNull() }, ) } else { content() @@ -31,7 +31,7 @@ private fun RecursiveProvideBeforeScreenContent( screenLifecycleContentProvider: ScreenLifecycleContentProvider, provideSaveableState: @Composable (suffixKey: String, content: @Composable () -> Unit) -> Unit, content: @Composable () -> Unit, - nextOrNull: () -> ScreenLifecycleContentProvider? + nextOrNull: () -> ScreenLifecycleContentProvider?, ) { val next = remember(screenLifecycleContentProvider, provideSaveableState, content, nextOrNull) { nextOrNull() } if (next != null) { @@ -40,13 +40,13 @@ private fun RecursiveProvideBeforeScreenContent( screenLifecycleContentProvider = next, provideSaveableState = provideSaveableState, content = content, - nextOrNull = nextOrNull + nextOrNull = nextOrNull, ) } screenLifecycleContentProvider.ProvideBeforeScreenContent( provideSaveableState = { suffixKey, _ -> provideSaveableState(suffixKey, recursiveContent) - } + }, ) { recursiveContent() } @@ -54,7 +54,7 @@ private fun RecursiveProvideBeforeScreenContent( screenLifecycleContentProvider.ProvideBeforeScreenContent( provideSaveableState = { suffixKey, content -> provideSaveableState(suffixKey, content) - } + }, ) { content() } diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/NavigatorScreenLifecycle.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/NavigatorScreenLifecycle.kt index 816ce844..59f2d752 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/NavigatorScreenLifecycle.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/lifecycle/NavigatorScreenLifecycle.kt @@ -11,6 +11,5 @@ public val LocalNavigatorScreenLifecycleProvider: ProvidableCompositionLocal