From 1c453b1b81f7f8ad0a4b6362ee53de7bec7268f8 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:16:57 +0700 Subject: [PATCH 01/11] About: Fix failed to load contributors --- .../uragiristereo/mikansei/feature/about/AboutViewModel.kt | 2 +- .../mikansei/feature/about/contibutor/ContributorItem.kt | 4 ++-- .../mikansei/feature/about/data/AboutRepositoryImpl.kt | 6 +++++- .../feature/about/domain/entity/GitHubContributor.kt | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutViewModel.kt b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutViewModel.kt index bfc60f5a..ccd779dc 100644 --- a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutViewModel.kt +++ b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutViewModel.kt @@ -30,7 +30,7 @@ class AboutViewModel( id = 52477630, avatarUrl = "https://avatars.githubusercontent.com/u/52477630?v=4", htmlUrl = "https://github.com/uragiristereo", - contributions = 0, + contributions = null, ) init { diff --git a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/contibutor/ContributorItem.kt b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/contibutor/ContributorItem.kt index 950863b3..e23da539 100644 --- a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/contibutor/ContributorItem.kt +++ b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/contibutor/ContributorItem.kt @@ -38,8 +38,8 @@ fun ContributorItem( modifier: Modifier = Modifier, ) { val contributions: Any = when { - item.contributions > 0 -> item.contributions - else -> "-" + item.contributions == null || item.contributions <= 0 -> "?" + else -> item.contributions } Row( diff --git a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/data/AboutRepositoryImpl.kt b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/data/AboutRepositoryImpl.kt index ad1caa63..10dcea4d 100644 --- a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/data/AboutRepositoryImpl.kt +++ b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/data/AboutRepositoryImpl.kt @@ -15,10 +15,14 @@ import retrofit2.converter.kotlinx.serialization.asConverterFactory class AboutRepositoryImpl( networkRepository: NetworkRepository, ) : AboutRepository { + private val json = Json { + ignoreUnknownKeys = true + } + private val githubClient: GitHubApi = Retrofit.Builder() .baseUrl("https://api.github.com") .client(networkRepository.okHttpClient) - .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) + .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) .build() .create(GitHubApi::class.java) diff --git a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/domain/entity/GitHubContributor.kt b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/domain/entity/GitHubContributor.kt index c4c6a3c4..db2a8b9f 100644 --- a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/domain/entity/GitHubContributor.kt +++ b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/domain/entity/GitHubContributor.kt @@ -5,5 +5,5 @@ data class GitHubContributor( val id: Int, val avatarUrl: String, val htmlUrl: String, - val contributions: Int, + val contributions: Int?, ) From 40a8230606d32de6bf080767f636e6812cac312e Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:35:10 +0700 Subject: [PATCH 02/11] User-Deactivation: Refactor navigation --- .../deactivation/UserDeactivationScreen.kt | 57 ++--- .../deactivation/UserDeactivationViewModel.kt | 12 +- .../core/UserDeactivationTopAppBar.kt | 18 +- .../user/deactivation/navigation/Page.kt | 12 -- .../navigation/UserDeactivationNavGraph.kt | 201 ++++++++++++------ .../navigation/UserDeactivationRoute.kt | 22 ++ 6 files changed, 184 insertions(+), 138 deletions(-) delete mode 100644 feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/Page.kt create mode 100644 feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt index 9e9ba074..fb182f3c 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt @@ -1,6 +1,5 @@ package com.uragiristereo.mikansei.feature.user.deactivation -import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides @@ -13,19 +12,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier -import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController import com.google.accompanist.insets.ui.Scaffold import com.uragiristereo.mikansei.core.product.component.ProductNavigationBarSpacer import com.uragiristereo.mikansei.core.ui.LocalScaffoldState import com.uragiristereo.mikansei.feature.user.deactivation.core.UserDeactivationTopAppBar -import com.uragiristereo.mikansei.feature.user.deactivation.in_app.UserDeactivationInAppConfirmationDialog -import com.uragiristereo.mikansei.feature.user.deactivation.navigation.Page import com.uragiristereo.mikansei.feature.user.deactivation.navigation.UserDeactivationNavGraph +import com.uragiristereo.mikansei.feature.user.deactivation.navigation.UserDeactivationRoute +import com.uragiristereo.serializednavigationextension.runtime.routeOf import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -37,25 +35,21 @@ fun UserDeactivationScreen( ) { val scaffoldState = LocalScaffoldState.current val activeUser by viewModel.activeUser.collectAsState() - val scope = rememberCoroutineScope() + val navController = rememberNavController() + val currentBackStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = currentBackStackEntry?.destination?.route - val popPage: () -> Unit = { - if (!viewModel.isLoading) { - when (viewModel.currentPage) { - Page.AGREEMENT -> onNavigateBack() - Page.METHODS -> viewModel.currentPage = Page.AGREEMENT - - Page.IN_APP -> { - viewModel.currentPage = Page.METHODS - - scope.launch { - delay(timeMillis = 500L) - viewModel.passwordTextField = TextFieldValue() - } - } + val currentPage = when (currentRoute) { + routeOf() -> UserDeactivationRoute.Agreement + routeOf() -> UserDeactivationRoute.Methods + routeOf() -> UserDeactivationRoute.InApp + routeOf() -> UserDeactivationRoute.InWeb + else -> UserDeactivationRoute.Agreement + } - Page.IN_BROWSER -> viewModel.currentPage = Page.METHODS - } + val popPage: () -> Unit = { + if (!navController.navigateUp()) { + onNavigateBack() } } @@ -88,25 +82,12 @@ fun UserDeactivationScreen( } } - BackHandler( - enabled = viewModel.currentPage != Page.AGREEMENT, - onBack = popPage, - ) - - UserDeactivationInAppConfirmationDialog( - isVisible = viewModel.showInAppConfirmationDialog, - onDismissRequest = { - viewModel.showInAppConfirmationDialog = false - }, - onConfirm = viewModel::deactivateAccount, - ) - Scaffold( scaffoldState = scaffoldState, topBar = { UserDeactivationTopAppBar( activeUserName = activeUser.name, - currentPage = viewModel.currentPage, + currentPage = currentPage, isNavigationButtonEnabled = !viewModel.isLoading, isLoading = viewModel.isLoading, onNavigateBack = popPage, @@ -121,8 +102,8 @@ fun UserDeactivationScreen( .windowInsetsPadding(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)), ) { innerPadding -> UserDeactivationNavGraph( + navController = navController, innerPadding = innerPadding, - viewModel = viewModel, ) } } diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationViewModel.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationViewModel.kt index cdbd41a9..fee79179 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationViewModel.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationViewModel.kt @@ -5,7 +5,6 @@ import android.content.Intent import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.compose.ui.text.input.TextFieldValue import androidx.core.net.toUri import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel @@ -16,7 +15,6 @@ import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.module.database.UserRepository import com.uragiristereo.mikansei.core.domain.usecase.DeactivateAccountUseCase import com.uragiristereo.mikansei.core.model.result.Result -import com.uragiristereo.mikansei.feature.user.deactivation.navigation.Page import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch @@ -35,21 +33,15 @@ class UserDeactivationViewModel( var isLoading by mutableStateOf(false) var showInAppConfirmationDialog by mutableStateOf(false) - var currentPage by savedStateHandle.saveable { - mutableStateOf(Page.AGREEMENT) - } var isConfirming by savedStateHandle.saveable { mutableStateOf(false) } - var passwordTextField by savedStateHandle.saveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue()) - } - fun deactivateAccount() { + fun deactivateAccount(password: String) { viewModelScope.launch { isLoading = true - when (val result = deactivateAccountUseCase(passwordTextField.text)) { + when (val result = deactivateAccountUseCase(password)) { is Result.Success -> channel.send(Event.OnDeactivateSuccess) is Result.Failed -> channel.send(Event.OnDeactivateFailed(result.message)) is Result.Error -> channel.send(Event.OnDeactivateFailed(result.t.toString())) diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationTopAppBar.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationTopAppBar.kt index 6767ec54..abc2ed2b 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationTopAppBar.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationTopAppBar.kt @@ -18,12 +18,12 @@ import androidx.compose.ui.unit.sp import com.uragiristereo.mikansei.core.product.component.ProductStatusBarSpacer import com.uragiristereo.mikansei.core.product.component.ProductTopAppBar import com.uragiristereo.mikansei.core.resources.R -import com.uragiristereo.mikansei.feature.user.deactivation.navigation.Page +import com.uragiristereo.mikansei.feature.user.deactivation.navigation.UserDeactivationRoute @Composable fun UserDeactivationTopAppBar( activeUserName: String, - currentPage: Page, + currentPage: UserDeactivationRoute, isLoading: Boolean, isNavigationButtonEnabled: Boolean, onNavigateBack: () -> Unit, @@ -31,20 +31,20 @@ fun UserDeactivationTopAppBar( ) { val progress by animateFloatAsState( targetValue = when (currentPage) { - Page.AGREEMENT -> 0.33f - Page.METHODS -> 0.66f - Page.IN_APP, Page.IN_BROWSER -> 1f + UserDeactivationRoute.Agreement -> 0.33f + UserDeactivationRoute.Methods -> 0.66f + UserDeactivationRoute.InApp, UserDeactivationRoute.InWeb -> 1f }, label = "ProgressSteps", ) val currentStep = when (currentPage) { - Page.AGREEMENT -> 1 - Page.METHODS -> 2 - Page.IN_APP, Page.IN_BROWSER -> 3 + UserDeactivationRoute.Agreement -> 1 + UserDeactivationRoute.Methods -> 2 + UserDeactivationRoute.InApp, UserDeactivationRoute.InWeb -> 3 } - val totalSteps = Page.TOTAL_STEPS + val totalSteps = UserDeactivationRoute.TOTAL_STEPS ProductStatusBarSpacer { ProductTopAppBar( diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/Page.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/Page.kt deleted file mode 100644 index f1009835..00000000 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/Page.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.uragiristereo.mikansei.feature.user.deactivation.navigation - -enum class Page { - AGREEMENT, - METHODS, - IN_APP, - IN_BROWSER; - - companion object { - const val TOTAL_STEPS = 3 - } -} diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt index 229d89bb..159b7a0a 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt @@ -1,98 +1,161 @@ package com.uragiristereo.mikansei.feature.user.deactivation.navigation -import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.input.TextFieldValue +import androidx.lifecycle.ViewModelStoreOwner +import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController import com.uragiristereo.mikansei.core.ui.animation.translateXFadeIn import com.uragiristereo.mikansei.core.ui.animation.translateXFadeOut import com.uragiristereo.mikansei.feature.user.deactivation.UserDeactivationViewModel import com.uragiristereo.mikansei.feature.user.deactivation.agreement.UserDeactivationAgreementScreen +import com.uragiristereo.mikansei.feature.user.deactivation.in_app.UserDeactivationInAppConfirmationDialog import com.uragiristereo.mikansei.feature.user.deactivation.in_app.UserDeactivationInAppScreen import com.uragiristereo.mikansei.feature.user.deactivation.in_web.UserDeactivationInWebScreen import com.uragiristereo.mikansei.feature.user.deactivation.methods.UserDeactivationMethodsScreen +import com.uragiristereo.serializednavigationextension.navigation.compose.NavHost +import com.uragiristereo.serializednavigationextension.navigation.compose.composable +import com.uragiristereo.serializednavigationextension.runtime.navigate +import org.koin.androidx.compose.koinViewModel @Composable fun UserDeactivationNavGraph( + navController: NavHostController, innerPadding: PaddingValues, - viewModel: UserDeactivationViewModel, modifier: Modifier = Modifier, ) { - val context = LocalContext.current - val activeUser by viewModel.activeUser.collectAsState() + val parentViewModelStoreOwner = requireNotNull(LocalViewModelStoreOwner.current) - AnimatedContent( - targetState = viewModel.currentPage, - transitionSpec = { - val forward = initialState < targetState - val transition = translateXFadeIn(forward) togetherWith - translateXFadeOut(forward) - - transition.apply { - targetContentZIndex = when { - forward -> 0f - else -> -1f - } - } + NavHost( + navController = navController, + startDestination = UserDeactivationRoute.Agreement, + enterTransition = { + translateXFadeIn(forward = true) + }, + exitTransition = { + translateXFadeOut(forward = true) + }, + popEnterTransition = { + translateXFadeIn(forward = false) + }, + popExitTransition = { + translateXFadeOut(forward = false) }, - label = "UserDeactivationPage", - modifier = modifier.fillMaxSize(), - ) { currentPageState -> - when (currentPageState) { - Page.AGREEMENT -> { - UserDeactivationAgreementScreen( - innerPadding = innerPadding, - activeUserId = activeUser.id, - isConfirming = viewModel.isConfirming, - onConfirmingChange = { - viewModel.isConfirming = it - }, - onProceedClick = { - viewModel.currentPage = Page.METHODS - }, - ) - } + modifier = modifier, + ) { + agreementRoute(navController, innerPadding, parentViewModelStoreOwner) + methodsRoute(navController, innerPadding) + inAppRoute(innerPadding, parentViewModelStoreOwner) + inWebRoute(innerPadding, parentViewModelStoreOwner) + } +} + +private fun NavGraphBuilder.agreementRoute( + navController: NavHostController, + innerPadding: PaddingValues, + parentViewModelStoreOwner: ViewModelStoreOwner, +) { + composable(UserDeactivationRoute.Agreement) { + val viewModel = koinViewModel( + viewModelStoreOwner = parentViewModelStoreOwner, + ) - Page.METHODS -> { - UserDeactivationMethodsScreen( - innerPadding = innerPadding, - onInAppClick = { - viewModel.currentPage = Page.IN_APP - }, - onInWebClick = { - viewModel.currentPage = Page.IN_BROWSER - }, - ) - } + val activeUser by viewModel.activeUser.collectAsState() + + UserDeactivationAgreementScreen( + innerPadding = innerPadding, + activeUserId = activeUser.id, + isConfirming = viewModel.isConfirming, + onConfirmingChange = { + viewModel.isConfirming = it + }, + onProceedClick = { + navController.navigate(UserDeactivationRoute.Methods) + }, + ) + } +} + +private fun NavGraphBuilder.methodsRoute( + navController: NavHostController, + innerPadding: PaddingValues, +) { + composable(UserDeactivationRoute.Methods) { + UserDeactivationMethodsScreen( + innerPadding = innerPadding, + onInAppClick = { + navController.navigate(UserDeactivationRoute.InApp) + }, + onInWebClick = { + navController.navigate(UserDeactivationRoute.InWeb) + }, + ) + } +} - Page.IN_APP -> { - UserDeactivationInAppScreen( - innerPadding = innerPadding, - isLoading = viewModel.isLoading, - password = viewModel.passwordTextField, - onPasswordChange = { - viewModel.passwordTextField = it - }, - onDeactivateClick = { - viewModel.showInAppConfirmationDialog = true - }, - ) - } +private fun NavGraphBuilder.inAppRoute( + innerPadding: PaddingValues, + parentViewModelStoreOwner: ViewModelStoreOwner, +) { + composable(UserDeactivationRoute.InApp) { + val viewModel = koinViewModel( + viewModelStoreOwner = parentViewModelStoreOwner, + ) - Page.IN_BROWSER -> { - UserDeactivationInWebScreen( - innerPadding = innerPadding, - onOpenWebClick = { - viewModel.openDeactivationWeb(context) - }, - onLogoutClick = viewModel::switchToAnonymousAndDelete, - ) - } + var passwordTextField by rememberSaveable(stateSaver = TextFieldValue.Saver) { + mutableStateOf(TextFieldValue()) } + + UserDeactivationInAppConfirmationDialog( + isVisible = viewModel.showInAppConfirmationDialog, + onDismissRequest = { + viewModel.showInAppConfirmationDialog = false + }, + onConfirm = { + viewModel.deactivateAccount(passwordTextField.text) + }, + ) + + UserDeactivationInAppScreen( + innerPadding = innerPadding, + isLoading = viewModel.isLoading, + password = passwordTextField, + onPasswordChange = { + passwordTextField = it + }, + onDeactivateClick = { + viewModel.showInAppConfirmationDialog = true + }, + ) + } +} + +private fun NavGraphBuilder.inWebRoute( + innerPadding: PaddingValues, + parentViewModelStoreOwner: ViewModelStoreOwner, +) { + composable(UserDeactivationRoute.InWeb) { + val context = LocalContext.current + + val viewModel = koinViewModel( + viewModelStoreOwner = parentViewModelStoreOwner, + ) + + UserDeactivationInWebScreen( + innerPadding = innerPadding, + onOpenWebClick = { + viewModel.openDeactivationWeb(context) + }, + onLogoutClick = viewModel::switchToAnonymousAndDelete, + ) } } diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt new file mode 100644 index 00000000..19bfef9a --- /dev/null +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt @@ -0,0 +1,22 @@ +package com.uragiristereo.mikansei.feature.user.deactivation.navigation + +import com.uragiristereo.serializednavigationextension.runtime.NavRoute +import kotlinx.serialization.Serializable + +sealed interface UserDeactivationRoute : NavRoute { + @Serializable + data object Agreement : UserDeactivationRoute + + @Serializable + data object Methods : UserDeactivationRoute + + @Serializable + data object InApp : UserDeactivationRoute + + @Serializable + data object InWeb : UserDeactivationRoute + + companion object { + const val TOTAL_STEPS = 3 + } +} From b25944d700dcd663d43a5e5fe644c83b91770eb5 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:01:35 +0700 Subject: [PATCH 03/11] Build: Replace navigation with official androidx --- app/build.gradle | 1 - core/ui/build.gradle | 2 +- gradle/libs.versions.toml | 7 ++----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d3063257..358156a9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -111,7 +111,6 @@ dependencies { implementation(libs.bundles.coil) implementation(libs.timber) implementation(libs.kotlinx.serialization.json) - implementation(libs.serialized.navigation.extension.serializer.kotlinx) playImplementation(platform(libs.firebase.bom)) playImplementation(libs.firebase.analytics) playImplementation(libs.firebase.crashlytics) diff --git a/core/ui/build.gradle b/core/ui/build.gradle index 5f515e77..471a1756 100644 --- a/core/ui/build.gradle +++ b/core/ui/build.gradle @@ -29,6 +29,6 @@ dependencies { api(libs.accompanist.insets.ui) implementation(libs.kotlinx.serialization.json) implementation(libs.timber) - api(libs.serialized.navigation.extension.compose) + api(libs.androidx.navigation) implementation(libs.bundles.coil) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e72a802e..152f18e0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ savedstate = "1.2.1" splashscreen = "1.0.1" datastore = "1.1.1" browser = "1.8.0" +navigation = "2.8.5" # Jetpack Compose compose = "1.7.3" @@ -34,7 +35,6 @@ gms = "4.4.2" # Etc. koin = "3.5.6" coil = "2.7.0" -serialized-navigation-extension = "e23f84fc1f" junit = "4.13.2" desugar-jdk-libs = "2.1.2" touchimageview = "3.2.1" @@ -61,6 +61,7 @@ androidx-savedstate = { module = "androidx.savedstate:savedstate-ktx", version.r androidx-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "splashscreen" } androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } androidx-browser = { module = "androidx.browser:browser", version.ref = "browser" } +androidx-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "navigation" } # Jetpack Compose compose = { module = "androidx.compose.ui:ui", version.ref = "compose" } @@ -110,10 +111,6 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa # Timber Logger timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } -# Serialized Navigation Extension -serialized-navigation-extension-compose = { module = "com.github.uragiristereo.serialized-navigation-extension:navigation-compose", version.ref = "serialized-navigation-extension" } -serialized-navigation-extension-serializer-kotlinx = { module = "com.github.uragiristereo.serialized-navigation-extension:serializer-kotlinx", version.ref = "serialized-navigation-extension" } - # AndroidX Media3 media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3" } media3-okhttp = { module = "androidx.media3:media3-datasource-okhttp", version.ref = "media3" } From 1c0f67dfdba97b13eea59838e3fb0d29068f740e Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:03:08 +0700 Subject: [PATCH 04/11] UI: Add helpers for navigation (1/2) --- .../mikansei/core/ui/navigation/NavRoute.kt | 22 +++++++++++ .../core/ui/navigation/SerializableNavType.kt | 39 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavRoute.kt create mode 100644 core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavRoute.kt new file mode 100644 index 00000000..645462ed --- /dev/null +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavRoute.kt @@ -0,0 +1,22 @@ +package com.uragiristereo.mikansei.core.ui.navigation + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.serializer +import kotlin.reflect.KClass + +interface NavRoute + +inline fun routeOf(): Int { + return routeOf(T::class) +} + +@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class) +fun routeOf(route: KClass): Int { + val serializer = route.serializer() + var hash = serializer.descriptor.serialName.hashCode() + for (i in 0 until serializer.descriptor.elementsCount) { + hash = 31 * hash + serializer.descriptor.getElementName(i).hashCode() + } + return hash +} diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt new file mode 100644 index 00000000..32e7f77e --- /dev/null +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt @@ -0,0 +1,39 @@ +package com.uragiristereo.mikansei.core.ui.navigation + +import android.net.Uri +import android.os.Bundle +import androidx.navigation.NavType +import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.serializer +import kotlin.reflect.KClass +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +@OptIn(InternalSerializationApi::class) +abstract class SerializableNavType(private val klass: KClass) : NavType(true) { + override fun get(bundle: Bundle, key: String): T? { + return Json.decodeFromString(klass.serializer(), requireNotNull(bundle.getString(key))) + } + + override fun parseValue(value: String): T { + return Json.decodeFromString(klass.serializer(), Uri.decode(value)) + } + + override fun put(bundle: Bundle, key: String, value: T) { + bundle.putString(key, Json.encodeToString(klass.serializer(), value)) + } + + override fun serializeAsValue(value: T): String { + return Uri.encode(Json.encodeToString(klass.serializer(), value)) + } +} + +inline fun navTypeMapOf(): Map> { + val navType = object : SerializableNavType(T::class) {} + + return mapOf( + typeOf() to navType, + typeOf() to navType, + ) +} From 395b1c7f2c8ed58844613e49b33a8464af2d4af3 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:03:20 +0700 Subject: [PATCH 05/11] Build: Add helpers for navigation (2/2) --- core/ui/build.gradle | 4 ++++ core/ui/navigation-rules.pro | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 core/ui/navigation-rules.pro diff --git a/core/ui/build.gradle b/core/ui/build.gradle index 471a1756..9fc74e35 100644 --- a/core/ui/build.gradle +++ b/core/ui/build.gradle @@ -8,6 +8,10 @@ plugins { android { namespace "com.uragiristereo.mikansei.core.ui" + defaultConfig { + consumerProguardFile("navigation-rules.pro") + } + buildFeatures { compose true } diff --git a/core/ui/navigation-rules.pro b/core/ui/navigation-rules.pro new file mode 100644 index 00000000..80c244cb --- /dev/null +++ b/core/ui/navigation-rules.pro @@ -0,0 +1,3 @@ +-keep class ** implements com.uragiristereo.mikansei.core.ui.navigation.NavRoute { + @kotlinx.serialization.SerialName ; +} From 185b921d60c92fa33a89843a2c543e3f9966d023 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:06:22 +0700 Subject: [PATCH 06/11] UI: Replace parent nav backstack entry retrieval method --- .../core/ui/extension/NavController.kt | 17 ++++++++++++++ .../core/ui/extension/ViewModelStoreOwner.kt | 22 ------------------- 2 files changed, 17 insertions(+), 22 deletions(-) create mode 100644 core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/NavController.kt delete mode 100644 core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/ViewModelStoreOwner.kt diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/NavController.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/NavController.kt new file mode 100644 index 00000000..5ed8584e --- /dev/null +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/NavController.kt @@ -0,0 +1,17 @@ +package com.uragiristereo.mikansei.core.ui.extension + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavController + +@Composable +fun NavController.rememberParentNavBackStackEntry(): NavBackStackEntry { + return remember(currentBackStackEntry) { + val destination = currentBackStackEntry?.destination + val parentId = requireNotNull(destination?.parent?.id) { + error("Destination id=${destination?.id} route=${destination?.route} doesn't have a parent") + } + getBackStackEntry(parentId) + } +} diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/ViewModelStoreOwner.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/ViewModelStoreOwner.kt deleted file mode 100644 index 50960d2e..00000000 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/extension/ViewModelStoreOwner.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.uragiristereo.mikansei.core.ui.extension - -import android.annotation.SuppressLint -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.lifecycle.ViewModelStoreOwner -import androidx.navigation.NavHostController - -@Composable -fun rememberParentViewModelStoreOwner( - navController: NavHostController, - parentRoute: String, -): ViewModelStoreOwner { - return remember(navController, parentRoute) { - object : ViewModelStoreOwner { - @SuppressLint("UnrememberedGetBackStackEntry") - override val viewModelStore = navController - .getBackStackEntry(parentRoute) - .viewModelStore - } - } -} From 1bea25a5fdeb9b735706ba961e9f9ebad875ba71 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:07:16 +0700 Subject: [PATCH 07/11] Update navigation usages --- .../com/uragiristereo/mikansei/MikanseiApp.kt | 4 - .../uragiristereo/mikansei/ui/MainScreen.kt | 14 +-- .../ui/appbars/MainBottomNavigationBar.kt | 15 ++- .../ui/appbars/MainNavigationItems.kt | 2 +- .../mikansei/ui/appbars/MainNavigationRail.kt | 15 ++- .../mikansei/ui/content/MainContentCompact.kt | 6 +- .../ui/content/MainContentMediumWide.kt | 8 +- .../ui/content/MainContentResponsive.kt | 6 +- .../mikansei/ui/navgraphs/BottomNavGraph.kt | 2 +- .../mikansei/ui/navgraphs/MainNavGraph.kt | 2 +- .../postfavoritevote/PostFavoriteVoteImpl.kt | 5 +- .../navigator/BottomSheetNavigator.kt | 23 ++-- .../mikansei/core/ui/navigation/HomeRoute.kt | 18 +-- .../mikansei/core/ui/navigation/MainRoute.kt | 2 - .../core/ui/navigation/SavedSearchesRoute.kt | 1 - .../core/ui/navigation/SettingsRoute.kt | 1 - .../mikansei/core/ui/navigation/UserRoute.kt | 1 - .../mikansei/feature/about/AboutModule.kt | 2 +- .../feature/filters/core/FiltersNavigation.kt | 2 +- .../feature/home/favorites/FavoritesModule.kt | 114 ++++++++---------- .../favgroup/addto/AddToFavGroupViewModel.kt | 5 +- .../favgroup/edit/EditFavGroupViewModel.kt | 5 +- .../favgroup/new/NewFavGroupViewModel.kt | 4 +- .../mikansei/feature/home/more/MoreScreen.kt | 2 +- .../feature/home/more/core/MoreNavigation.kt | 3 +- .../feature/home/posts/PostsViewModel.kt | 4 +- .../home/posts/core/PostsNavigation.kt | 22 ++-- .../home/posts/more/PostMoreViewModel.kt | 5 +- .../home/posts/share/ShareViewModel.kt | 5 +- .../mikansei/feature/home/HomeNavigation.kt | 17 ++- .../mikansei/feature/image/ImageScreen.kt | 1 - .../mikansei/feature/image/ViewerViewModel.kt | 5 +- .../feature/image/core/ImageNavigation.kt | 5 +- .../feature/image/image/ImageViewModel.kt | 5 +- .../image/more/MoreBottomSheetViewModel.kt | 5 +- .../feature/image/video/VideoViewModel.kt | 5 +- .../saved_searches/SavedSearchesModule.kt | 56 ++++----- .../NewOrEditSavedSearchViewModel.kt | 7 +- .../feature/search/SearchViewModel.kt | 4 +- .../feature/search/core/SearchNavigation.kt | 10 +- .../settings/core/SettingsNavigation.kt | 9 +- .../deactivation/UserDeactivationScreen.kt | 4 +- .../core/UserDeactivationNavigation.kt | 5 +- .../navigation/UserDeactivationNavGraph.kt | 13 +- .../navigation/UserDeactivationRoute.kt | 2 +- .../core/UserDelegationSettingsNavigation.kt | 2 +- .../user/login/core/LoginNavigation.kt | 2 +- .../feature/user/manage/ManageUserScreen.kt | 2 +- .../user/manage/core/ManageNavigation.kt | 3 +- .../user/settings/UserSettingsScreen.kt | 2 +- .../settings/core/UserSettingsNavigation.kt | 3 +- .../mikansei/feature/user/UserNavigation.kt | 7 +- 52 files changed, 214 insertions(+), 258 deletions(-) diff --git a/app/src/main/java/com/uragiristereo/mikansei/MikanseiApp.kt b/app/src/main/java/com/uragiristereo/mikansei/MikanseiApp.kt index fe41f20e..e486d2e1 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/MikanseiApp.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/MikanseiApp.kt @@ -8,9 +8,6 @@ import android.os.Build.VERSION.SDK_INT import coil.ImageLoader import coil.ImageLoaderFactory import com.uragiristereo.mikansei.core.domain.module.network.NetworkRepository -import com.uragiristereo.serializednavigationextension.runtime.installSerializer -import com.uragiristereo.serializednavigationextension.serializer.KotlinxSerializer -import kotlinx.serialization.json.Json import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.component.KoinComponent @@ -25,7 +22,6 @@ class MikanseiApp : Application(), ImageLoaderFactory, KoinComponent { super.onCreate() Timber.plant(Timber.DebugTree()) - installSerializer(KotlinxSerializer(json = Json { ignoreUnknownKeys = true })) if (SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel("downloads", "Downloads", NotificationManager.IMPORTANCE_LOW) diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/MainScreen.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/MainScreen.kt index 81655ff2..a5066ea9 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/MainScreen.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/MainScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.navigation.NavDestination.Companion.hasRoute import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState @@ -45,15 +46,14 @@ import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottom import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.rememberBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.navigation.HomeRoutesString import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute import com.uragiristereo.mikansei.core.ui.navigation.NestedNavigationRoutes +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.core.ui.rememberWindowSizeHorizontal import com.uragiristereo.mikansei.core.ui.rememberWindowSizeVertical import com.uragiristereo.mikansei.ui.content.MainContentResponsive import com.uragiristereo.mikansei.ui.core.ShareDownloadDialog import com.uragiristereo.mikansei.ui.navgraphs.BottomNavGraph -import com.uragiristereo.serializednavigationextension.runtime.NavRoute -import com.uragiristereo.serializednavigationextension.runtime.navigate -import com.uragiristereo.serializednavigationextension.runtime.routeOf import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -73,16 +73,16 @@ fun MainScreen( val navBackStackEntry by navController.currentBackStackEntryAsState() val backStack by navController.currentBackStack.collectAsState() - val currentRoute = navBackStackEntry?.destination?.route + val currentRoute = navBackStackEntry?.destination?.id val previousRoute by remember { derivedStateOf { val backStackWithoutNested = backStack.filter { - it.destination.route !in NestedNavigationRoutes + it.destination.id !in NestedNavigationRoutes } runCatching { - backStackWithoutNested[backStackWithoutNested.size - 2].destination.route + backStackWithoutNested[backStackWithoutNested.size - 2].destination.id }.getOrElse { null } @@ -207,7 +207,7 @@ fun MainScreen( ) BackHandler( - enabled = !viewModel.confirmExit && currentRoute == routeOf(), + enabled = !viewModel.confirmExit && navBackStackEntry?.destination?.hasRoute() == true, onBack = { (context as Activity).finishAffinity() }, diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainBottomNavigationBar.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainBottomNavigationBar.kt index db84636a..99f3b181 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainBottomNavigationBar.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainBottomNavigationBar.kt @@ -20,14 +20,13 @@ import com.uragiristereo.mikansei.core.ui.extension.backgroundElevation import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.HomeRoutesString import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.serializednavigationextension.runtime.NavRoute -import com.uragiristereo.serializednavigationextension.runtime.route -import com.uragiristereo.serializednavigationextension.runtime.routeOf +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf @Composable fun MainBottomNavigationBar( - currentRoute: String?, - previousRoute: String?, + currentRoute: Int?, + previousRoute: Int?, onNavigate: (NavRoute) -> Unit, onNavigateSearch: () -> Unit, onRequestScrollToTop: () -> Unit, @@ -59,7 +58,7 @@ fun MainBottomNavigationBar( windowInsets = WindowInsets.navigationBars, ) { MainNavigationItems.entries.forEach { item -> - val itemRouteString = item.route.route + val itemRouteString = routeOf(item.route::class) val currentRouteIsItem = currentRoute == itemRouteString val previousRouteIsItem = previousRoute == itemRouteString @@ -84,11 +83,11 @@ fun MainBottomNavigationBar( }, onClick = { when { - listOf(item.route.route, currentRoute).all { + listOf(itemRouteString, currentRoute).all { it == routeOf() } -> onRequestScrollToTop() - item.route.route == routeOf() -> onNavigateSearch() + itemRouteString == routeOf() -> onNavigateSearch() else -> onNavigate(item.route) } }, diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationItems.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationItems.kt index 61fef916..1b175418 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationItems.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationItems.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.Stable import com.uragiristereo.mikansei.core.resources.R import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.serializednavigationextension.runtime.NavRoute +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute @Stable enum class MainNavigationItems( diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationRail.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationRail.kt index 45a3c7ab..69c72237 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationRail.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/appbars/MainNavigationRail.kt @@ -16,14 +16,13 @@ import com.uragiristereo.mikansei.core.ui.extension.backgroundElevation import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.HomeRoutesString import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.serializednavigationextension.runtime.NavRoute -import com.uragiristereo.serializednavigationextension.runtime.route -import com.uragiristereo.serializednavigationextension.runtime.routeOf +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf @Composable fun MainNavigationRail( - currentRoute: String?, - previousRoute: String?, + currentRoute: Int?, + previousRoute: Int?, onNavigate: (NavRoute) -> Unit, onNavigateSearch: () -> Unit, onRequestScrollToTop: () -> Unit, @@ -39,7 +38,7 @@ fun MainNavigationRail( modifier = Modifier.fillMaxHeight(), ) { MainNavigationItems.entries.forEach { item -> - val itemRouteString = item.route.route + val itemRouteString = routeOf(item.route::class) val currentRouteIsItem = currentRoute == itemRouteString val previousRouteIsItem = previousRoute == itemRouteString @@ -64,11 +63,11 @@ fun MainNavigationRail( }, onClick = { when { - listOf(item.route.route, currentRoute).all { + listOf(itemRouteString, currentRoute).all { it == routeOf() } -> onRequestScrollToTop() - item.route.route == routeOf() -> onNavigateSearch() + itemRouteString == routeOf() -> onNavigateSearch() else -> onNavigate(item.route) } }, diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentCompact.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentCompact.kt index deae11d7..423162d3 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentCompact.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentCompact.kt @@ -10,14 +10,14 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier import com.google.accompanist.insets.ui.Scaffold import com.uragiristereo.mikansei.core.ui.LocalMainScaffoldPadding +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute import com.uragiristereo.mikansei.ui.appbars.MainBottomNavigationBar -import com.uragiristereo.serializednavigationextension.runtime.NavRoute @Composable fun MainContentCompact( navigationBarsVisible: Boolean, - currentRoute: String?, - previousRoute: String?, + currentRoute: Int?, + previousRoute: Int?, onNavigate: (NavRoute) -> Unit, onNavigateSearch: () -> Unit, onRequestScrollToTop: () -> Unit, diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentMediumWide.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentMediumWide.kt index 6cc7c56e..191e1172 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentMediumWide.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentMediumWide.kt @@ -36,15 +36,15 @@ import com.uragiristereo.mikansei.core.ui.extension.backgroundElevation import com.uragiristereo.mikansei.core.ui.extension.copy import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.ui.appbars.MainNavigationRail -import com.uragiristereo.serializednavigationextension.runtime.NavRoute -import com.uragiristereo.serializednavigationextension.runtime.routeOf @Composable fun MainContentMediumWide( navigationBarsVisible: Boolean, - currentRoute: String?, - previousRoute: String?, + currentRoute: Int?, + previousRoute: Int?, navigationRailPadding: Dp, onNavigationRailPaddingChange: (Dp) -> Unit, onNavigate: (NavRoute) -> Unit, diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentResponsive.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentResponsive.kt index 99dc795f..19c3e0b0 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentResponsive.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/content/MainContentResponsive.kt @@ -19,15 +19,15 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import com.uragiristereo.mikansei.core.ui.LocalWindowSizeHorizontal import com.uragiristereo.mikansei.core.ui.WindowSize +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute import com.uragiristereo.mikansei.ui.navgraphs.MainNavGraph -import com.uragiristereo.serializednavigationextension.runtime.NavRoute @Composable fun MainContentResponsive( navController: NavHostController, navigationBarsVisible: Boolean, - currentRoute: String?, - previousRoute: String?, + currentRoute: Int?, + previousRoute: Int?, navigationRailPadding: Dp, testMode: Boolean, onNavigationRailPaddingChange: (Dp) -> Unit, diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/BottomNavGraph.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/BottomNavGraph.kt index 86a8d77a..74d28bf3 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/BottomNavGraph.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/BottomNavGraph.kt @@ -29,7 +29,7 @@ fun BottomNavGraph( NavHost( navController = bottomSheetNavigator.navController, - startDestination = BottomSheetNavigator.INDEX_ROUTE, + startDestination = BottomSheetNavigator.Index, enterTransition = { EnterTransition.None }, exitTransition = { ExitTransition.None }, modifier = modifier.fillMaxWidth(), diff --git a/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/MainNavGraph.kt b/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/MainNavGraph.kt index 470546d3..b374935d 100644 --- a/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/MainNavGraph.kt +++ b/app/src/main/java/com/uragiristereo/mikansei/ui/navgraphs/MainNavGraph.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost import com.uragiristereo.mikansei.core.ui.animation.translateXFadeIn import com.uragiristereo.mikansei.core.ui.animation.translateXFadeOut import com.uragiristereo.mikansei.core.ui.navigation.MainRoute @@ -16,7 +17,6 @@ import com.uragiristereo.mikansei.feature.search.core.searchRoute import com.uragiristereo.mikansei.feature.settings.core.settingsGraph import com.uragiristereo.mikansei.feature.user.userGraph import com.uragiristereo.mikansei.ui.MainViewModel -import com.uragiristereo.serializednavigationextension.navigation.compose.NavHost import org.koin.androidx.compose.koinViewModel @Composable diff --git a/core/product/src/main/java/com/uragiristereo/mikansei/core/product/shared/postfavoritevote/PostFavoriteVoteImpl.kt b/core/product/src/main/java/com/uragiristereo/mikansei/core/product/shared/postfavoritevote/PostFavoriteVoteImpl.kt index f4bcbf30..979684e8 100644 --- a/core/product/src/main/java/com/uragiristereo/mikansei/core/product/shared/postfavoritevote/PostFavoriteVoteImpl.kt +++ b/core/product/src/main/java/com/uragiristereo/mikansei/core/product/shared/postfavoritevote/PostFavoriteVoteImpl.kt @@ -6,13 +6,14 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.PostVote import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Profile import com.uragiristereo.mikansei.core.domain.module.database.UserRepository import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch @@ -28,7 +29,7 @@ open class PostFavoriteVoteImpl : ViewModel(), PostFavoriteVote, KoinComponent { private val activeUser: Profile get() = userRepository.active.value - override var post = savedStateHandle.navArgsOf()!!.post + override var post = savedStateHandle.toRoute(PostNavType).post private val post2 by lazy { post } diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/modalbottomsheet/navigator/BottomSheetNavigator.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/modalbottomsheet/navigator/BottomSheetNavigator.kt index 28e82337..6ed8457d 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/modalbottomsheet/navigator/BottomSheetNavigator.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/modalbottomsheet/navigator/BottomSheetNavigator.kt @@ -18,16 +18,21 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.navigation.NavDestination.Companion.hasRoute import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.modalbottomsheet.ModalBottomSheetState2 +import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.BottomSheetNavigator.Index import com.uragiristereo.mikansei.core.ui.modalbottomsheet.rememberModalBottomSheetState2 +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.serialization.Serializable import timber.log.Timber val LocalBottomSheetNavigator = staticCompositionLocalOf { error("No LocalBottomSheetNavigator provided!") } @@ -77,13 +82,12 @@ class BottomSheetNavigator( block: (NavHostController) -> Unit, ) { val currentBackStackEntry = navController.currentBackStackEntry - val currentRoute = currentBackStackEntry?.destination?.route if (!bottomSheetState.isAnimationRunning) { coroutineScope.launch(SupervisorJob()) { isNavigating = true - if (currentRoute != INDEX_ROUTE) { + if (currentBackStackEntry?.destination?.hasRoute() != true) { bottomSheetState.hide() if (popBackStack) { @@ -94,7 +98,7 @@ class BottomSheetNavigator( block(navController) coroutineScope.launch(SupervisorJob()) { - if (currentRoute != INDEX_ROUTE) { + if (currentBackStackEntry?.destination?.hasRoute() != true) { delay(timeMillis = 500L) } @@ -115,14 +119,15 @@ class BottomSheetNavigator( } companion object { - const val INDEX_ROUTE = "index" - fun indexRoute(builder: NavGraphBuilder) { - builder.composable(route = INDEX_ROUTE) { + builder.composable { Spacer(modifier = Modifier.size(1.dp)) } } } + + @Serializable + data object Index : NavRoute } @OptIn(ExperimentalMaterialApi::class) @@ -132,13 +137,13 @@ fun InterceptBackGestureForBottomSheetNavigator() { val scope = rememberCoroutineScope() BackHandler(enabled = bottomSheetNavigator.bottomSheetState.isVisible) { - val previousRoute = bottomSheetNavigator.navController.previousBackStackEntry?.destination?.route + val previousRoute = bottomSheetNavigator.navController.previousBackStackEntry?.destination?.id scope.launch(SupervisorJob()) { bottomSheetNavigator.isNavigating = true bottomSheetNavigator.bottomSheetState.hide() - if (previousRoute !in listOf(null, BottomSheetNavigator.INDEX_ROUTE)) { + if (previousRoute !in listOf(null, routeOf())) { bottomSheetNavigator.navController.popBackStack() delay(timeMillis = 300L) bottomSheetNavigator.expand() @@ -171,7 +176,7 @@ fun NavigateToIndexWhenBottomSheetNavigatorHidden() { if (!bottomSheetNavigator.bottomSheetState.isVisible && !bottomSheetNavigator.isNavigating) { Timber.d("popped") - bottomSheetNavigator.navController.navigate(BottomSheetNavigator.INDEX_ROUTE) { + bottomSheetNavigator.navController.navigate(Index) { popUpTo(id = 0) } } diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt index 09cfce1e..4c3734af 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt @@ -1,9 +1,8 @@ package com.uragiristereo.mikansei.core.ui.navigation import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Favorite +import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.SavedSearch import com.uragiristereo.mikansei.core.model.danbooru.Post -import com.uragiristereo.serializednavigationextension.runtime.NavRoute -import com.uragiristereo.serializednavigationextension.runtime.routeOf import kotlinx.serialization.Serializable sealed interface HomeRoute : NavRoute { @@ -53,9 +52,12 @@ sealed interface HomeRoute : NavRoute { ) : HomeRoute } -val HomeRoutesString: List - get() = listOf( - routeOf(), - routeOf(), - routeOf(), - ) +val HomeRoutesString = listOf( + routeOf(), + routeOf(), + routeOf(), +) + +val PostNavType = navTypeMapOf() +val FavoriteNavType = navTypeMapOf() +val SavedSearchTypes = navTypeMapOf() diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/MainRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/MainRoute.kt index b6d3a2b0..3cc03cb8 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/MainRoute.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/MainRoute.kt @@ -1,8 +1,6 @@ package com.uragiristereo.mikansei.core.ui.navigation import com.uragiristereo.mikansei.core.model.danbooru.Post -import com.uragiristereo.serializednavigationextension.runtime.NavRoute -import com.uragiristereo.serializednavigationextension.runtime.routeOf import kotlinx.serialization.Serializable sealed interface MainRoute : NavRoute { diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt index 28a98e0e..da202e02 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt @@ -1,7 +1,6 @@ package com.uragiristereo.mikansei.core.ui.navigation import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.SavedSearch -import com.uragiristereo.serializednavigationextension.runtime.NavRoute import kotlinx.serialization.Serializable sealed interface SavedSearchesRoute : NavRoute { diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SettingsRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SettingsRoute.kt index 150036f3..acfe7e69 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SettingsRoute.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SettingsRoute.kt @@ -1,6 +1,5 @@ package com.uragiristereo.mikansei.core.ui.navigation -import com.uragiristereo.serializednavigationextension.runtime.NavRoute import kotlinx.serialization.Serializable sealed interface SettingsRoute : NavRoute { diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/UserRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/UserRoute.kt index aaa579f0..8789dc22 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/UserRoute.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/UserRoute.kt @@ -1,6 +1,5 @@ package com.uragiristereo.mikansei.core.ui.navigation -import com.uragiristereo.serializednavigationextension.runtime.NavRoute import kotlinx.serialization.Serializable sealed interface UserRoute : NavRoute { diff --git a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutModule.kt b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutModule.kt index 9ac77fb5..f9d3a828 100644 --- a/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutModule.kt +++ b/feature/about/src/main/java/com/uragiristereo/mikansei/feature/about/AboutModule.kt @@ -2,10 +2,10 @@ package com.uragiristereo.mikansei.feature.about import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.navigation.MainRoute import com.uragiristereo.mikansei.feature.about.data.AboutRepositoryImpl import com.uragiristereo.mikansei.feature.about.domain.AboutRepository -import com.uragiristereo.serializednavigationextension.navigation.compose.composable import org.koin.androidx.viewmodel.dsl.viewModelOf import org.koin.core.module.dsl.scopedOf import org.koin.dsl.bind diff --git a/feature/filters/src/main/java/com/uragiristereo/mikansei/feature/filters/core/FiltersNavigation.kt b/feature/filters/src/main/java/com/uragiristereo/mikansei/feature/filters/core/FiltersNavigation.kt index 21e85192..5e5d49a1 100644 --- a/feature/filters/src/main/java/com/uragiristereo/mikansei/feature/filters/core/FiltersNavigation.kt +++ b/feature/filters/src/main/java/com/uragiristereo/mikansei/feature/filters/core/FiltersNavigation.kt @@ -2,9 +2,9 @@ package com.uragiristereo.mikansei.feature.filters.core import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.navigation.MainRoute import com.uragiristereo.mikansei.feature.filters.FiltersScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable fun NavGraphBuilder.filtersRoute( navController: NavHostController, diff --git a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/FavoritesModule.kt b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/FavoritesModule.kt index b1655cc4..d0190acb 100644 --- a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/FavoritesModule.kt +++ b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/FavoritesModule.kt @@ -6,10 +6,14 @@ import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController -import com.uragiristereo.mikansei.core.ui.extension.rememberParentViewModelStoreOwner +import androidx.navigation.compose.composable +import androidx.navigation.toRoute +import com.uragiristereo.mikansei.core.ui.extension.rememberParentNavBackStackEntry import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottomSheetNavigator +import com.uragiristereo.mikansei.core.ui.navigation.FavoriteNavType import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import com.uragiristereo.mikansei.feature.home.favorites.favgroup.addto.AddToFavGroupContent import com.uragiristereo.mikansei.feature.home.favorites.favgroup.addto.AddToFavGroupViewModel import com.uragiristereo.mikansei.feature.home.favorites.favgroup.delete.DeleteFavGroupContent @@ -19,9 +23,6 @@ import com.uragiristereo.mikansei.feature.home.favorites.favgroup.more.FavGroupM import com.uragiristereo.mikansei.feature.home.favorites.favgroup.more.FavGroupMoreViewModel import com.uragiristereo.mikansei.feature.home.favorites.favgroup.new.NewFavGroupScreen import com.uragiristereo.mikansei.feature.home.favorites.favgroup.new.NewFavGroupViewModel -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate -import com.uragiristereo.serializednavigationextension.runtime.routeOf import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.dsl.viewModelOf import org.koin.dsl.module @@ -37,11 +38,7 @@ val favoritesModule = module { fun NavGraphBuilder.favoritesRoute(navController: NavHostController) { composable { val bottomSheetNavigator = LocalBottomSheetNavigator.current - - val homeViewModelStoreOwner = rememberParentViewModelStoreOwner( - navController = navController, - parentRoute = routeOf(), - ) + val homeViewModelStoreOwner = navController.rememberParentNavBackStackEntry() CompositionLocalProvider(LocalViewModelStoreOwner provides homeViewModelStoreOwner) { FavoritesScreen( @@ -67,12 +64,8 @@ fun NavGraphBuilder.favoritesRoute(navController: NavHostController) { } } - composable(defaultValue = MainRoute.NewFavGroup()) { - val homeViewModelStoreOwner = rememberParentViewModelStoreOwner( - navController = navController, - parentRoute = routeOf(), - ) - + composable { + val homeViewModelStoreOwner = navController.rememberParentNavBackStackEntry() val favoritesViewModel: FavoritesViewModel = koinViewModel(viewModelStoreOwner = homeViewModelStoreOwner) NewFavGroupScreen( @@ -81,12 +74,8 @@ fun NavGraphBuilder.favoritesRoute(navController: NavHostController) { ) } - composable { - val homeViewModelStoreOwner = rememberParentViewModelStoreOwner( - navController = navController, - parentRoute = routeOf(), - ) - + composable(FavoriteNavType) { + val homeViewModelStoreOwner = navController.rememberParentNavBackStackEntry() val favoritesViewModel: FavoritesViewModel = koinViewModel(viewModelStoreOwner = homeViewModelStoreOwner) EditFavGroupScreen( @@ -98,7 +87,7 @@ fun NavGraphBuilder.favoritesRoute(navController: NavHostController) { @OptIn(ExperimentalMaterialApi::class) fun NavGraphBuilder.favoritesBottomRoute(navController: NavHostController) { - composable { + composable(PostNavType) { val bottomSheetNavigator = LocalBottomSheetNavigator.current AddToFavGroupContent( @@ -111,59 +100,50 @@ fun NavGraphBuilder.favoritesBottomRoute(navController: NavHostController) { ) } - composable { - val args = rememberNavArgsOf() + composable(FavoriteNavType) { entry -> + val args = entry.toRoute() - if (args != null) { - val bottomSheetNavigator = LocalBottomSheetNavigator.current - val favoriteGroup = args.favoriteGroup + val bottomSheetNavigator = LocalBottomSheetNavigator.current + val favoriteGroup = args.favoriteGroup - FavGroupMoreContent( - onDismiss = bottomSheetNavigator.bottomSheetState::hide, - favoriteGroup = favoriteGroup, - onFavGroupClick = { - bottomSheetNavigator.runHiding { - val tags = "favgroup:${favoriteGroup.id} " + FavGroupMoreContent( + onDismiss = bottomSheetNavigator.bottomSheetState::hide, + favoriteGroup = favoriteGroup, + onFavGroupClick = { + bottomSheetNavigator.runHiding { + val tags = "favgroup:${favoriteGroup.id} " - navController.navigate(HomeRoute.Posts(tags)) { - popUpTo(id = navController.graph.findStartDestination().id) - } - } - }, - onEditFavGroupClick = { - bottomSheetNavigator.runHiding { - navController.navigate(HomeRoute.EditFavoriteGroup(favoriteGroup)) - } - }, - onDeleteFavGroupClick = { - bottomSheetNavigator.navigate { - it.navigate(HomeRoute.DeleteFavoriteGroup(favoriteGroup)) + navController.navigate(HomeRoute.Posts(tags)) { + popUpTo(id = navController.graph.findStartDestination().id) } - }, - ) - } + } + }, + onEditFavGroupClick = { + bottomSheetNavigator.runHiding { + navController.navigate(HomeRoute.EditFavoriteGroup(favoriteGroup)) + } + }, + onDeleteFavGroupClick = { + bottomSheetNavigator.navigate { + it.navigate(HomeRoute.DeleteFavoriteGroup(favoriteGroup)) + } + }, + ) } - composable { + composable(FavoriteNavType) { entry -> val bottomSheetNavigator = LocalBottomSheetNavigator.current - val args = rememberNavArgsOf() - - val homeViewModelStoreOwner = rememberParentViewModelStoreOwner( - navController = navController, - parentRoute = routeOf(), - ) - + val args = entry.toRoute() + val homeViewModelStoreOwner = navController.rememberParentNavBackStackEntry() val favoritesViewModel: FavoritesViewModel = koinViewModel(viewModelStoreOwner = homeViewModelStoreOwner) - if (args != null) { - DeleteFavGroupContent( - favoriteGroup = args.favoriteGroup, - onDeleteClick = { - bottomSheetNavigator.runHiding { - favoritesViewModel.deleteFavoriteGroup(args.favoriteGroup) - } - }, - ) - } + DeleteFavGroupContent( + favoriteGroup = args.favoriteGroup, + onDeleteClick = { + bottomSheetNavigator.runHiding { + favoritesViewModel.deleteFavoriteGroup(args.favoriteGroup) + } + }, + ) } } diff --git a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/addto/AddToFavGroupViewModel.kt b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/addto/AddToFavGroupViewModel.kt index f562b19d..c86d26fa 100644 --- a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/addto/AddToFavGroupViewModel.kt +++ b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/addto/AddToFavGroupViewModel.kt @@ -7,13 +7,14 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Favorite import com.uragiristereo.mikansei.core.domain.usecase.GetFavoriteGroupsUseCase import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import com.uragiristereo.mikansei.feature.home.favorites.favgroup.addto.core.FavoriteGroup -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import timber.log.Timber @@ -24,7 +25,7 @@ class AddToFavGroupViewModel( private val danbooruRepository: DanbooruRepository, private val getFavoriteGroupsUseCase: GetFavoriteGroupsUseCase, ) : ViewModel() { - val post = checkNotNull(savedStateHandle.navArgsOf()).post + val post = savedStateHandle.toRoute(PostNavType).post var items by mutableStateOf>(listOf()) private set diff --git a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/edit/EditFavGroupViewModel.kt b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/edit/EditFavGroupViewModel.kt index 3cda11d9..cb679457 100644 --- a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/edit/EditFavGroupViewModel.kt +++ b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/edit/EditFavGroupViewModel.kt @@ -11,12 +11,13 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi import androidx.lifecycle.viewmodel.compose.saveable +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.extension.strip +import com.uragiristereo.mikansei.core.ui.navigation.FavoriteNavType import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.feature.home.favorites.favgroup.new.core.FabState -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch @@ -26,7 +27,7 @@ class EditFavGroupViewModel( savedStateHandle: SavedStateHandle, private val danbooruRepository: DanbooruRepository, ) : ViewModel() { - private val navArgs = checkNotNull(savedStateHandle.navArgsOf()) + private val navArgs = savedStateHandle.toRoute(FavoriteNavType) val favoriteGroup = navArgs.favoriteGroup private val spaceSeparatedPostIds = favoriteGroup.postIds.joinToString(separator = " ") diff --git a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/new/NewFavGroupViewModel.kt b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/new/NewFavGroupViewModel.kt index 55f26ae6..b7ec6dd3 100644 --- a/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/new/NewFavGroupViewModel.kt +++ b/feature/home/favorites/src/main/java/com/uragiristereo/mikansei/feature/home/favorites/favgroup/new/NewFavGroupViewModel.kt @@ -10,12 +10,12 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi import androidx.lifecycle.viewmodel.compose.saveable +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.usecase.GetFavoriteGroupsUseCase import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.navigation.MainRoute import com.uragiristereo.mikansei.feature.home.favorites.favgroup.new.core.FabState -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow @@ -29,7 +29,7 @@ class NewFavGroupViewModel( private val danbooruRepository: DanbooruRepository, private val getFavoriteGroupsUseCase: GetFavoriteGroupsUseCase, ) : ViewModel() { - val postId = savedStateHandle.navArgsOf(MainRoute.NewFavGroup()).postId + val postId = savedStateHandle.toRoute().postId private val channel = Channel() val event = channel.receiveAsFlow() diff --git a/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/MoreScreen.kt b/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/MoreScreen.kt index e5dc097b..0884c83f 100644 --- a/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/MoreScreen.kt +++ b/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/MoreScreen.kt @@ -43,11 +43,11 @@ import com.uragiristereo.mikansei.core.ui.extension.plus import com.uragiristereo.mikansei.core.ui.extension.versionName import com.uragiristereo.mikansei.core.ui.extension.verticalOnly import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.home.more.core.MoreTopAppBar import com.uragiristereo.mikansei.feature.home.more.core.NavigationItem import com.uragiristereo.mikansei.feature.home.more.core.UserHeader -import com.uragiristereo.serializednavigationextension.runtime.NavRoute import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel diff --git a/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/core/MoreNavigation.kt b/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/core/MoreNavigation.kt index b7692fde..c90deb1c 100644 --- a/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/core/MoreNavigation.kt +++ b/feature/home/more/src/main/java/com/uragiristereo/mikansei/feature/home/more/core/MoreNavigation.kt @@ -2,12 +2,11 @@ package com.uragiristereo.mikansei.feature.home.more.core import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.InterceptBackGestureForBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.feature.home.more.MoreScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate fun NavGraphBuilder.moreRoute(mainNavController: NavHostController) { composable { diff --git a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/PostsViewModel.kt b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/PostsViewModel.kt index 8d46df94..0780ceb7 100644 --- a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/PostsViewModel.kt +++ b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/PostsViewModel.kt @@ -13,6 +13,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi import androidx.lifecycle.viewmodel.compose.saveable +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Profile import com.uragiristereo.mikansei.core.domain.module.database.SessionRepository import com.uragiristereo.mikansei.core.domain.module.database.UserRepository @@ -26,7 +27,6 @@ import com.uragiristereo.mikansei.core.ui.entity.immutableListOf import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.feature.home.posts.state.PostsContentState import com.uragiristereo.mikansei.feature.home.posts.state.PostsLoadingState -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob @@ -49,7 +49,7 @@ class PostsViewModel( private val sessionRepository: SessionRepository, private val getPostsUseCase: GetPostsUseCase, ) : ViewModel() { - val tags = savedStateHandle.navArgsOf()?.tags ?: "" + val tags = savedStateHandle.toRoute().tags private val channel = Channel() val event = channel.receiveAsFlow() diff --git a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/core/PostsNavigation.kt b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/core/PostsNavigation.kt index 89b84381..815b03f1 100644 --- a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/core/PostsNavigation.kt +++ b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/core/PostsNavigation.kt @@ -8,6 +8,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.model.danbooru.Post import com.uragiristereo.mikansei.core.ui.LocalLambdaOnDownload import com.uragiristereo.mikansei.core.ui.LocalLambdaOnShare @@ -15,13 +17,12 @@ import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.InterceptBa import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchesRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.feature.home.posts.PostsScreen import com.uragiristereo.mikansei.feature.home.posts.more.PostMoreContent import com.uragiristereo.mikansei.feature.home.posts.share.ShareContent -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate -import com.uragiristereo.serializednavigationextension.runtime.routeOf @SuppressLint("RestrictedApi") fun NavGraphBuilder.postsRoute( @@ -37,10 +38,9 @@ fun NavGraphBuilder.postsRoute( ) } - composable( - defaultValue = HomeRoute.Posts(), + composable( enterTransition = { - when (initialState.destination.route) { + when (initialState.destination.id) { routeOf() -> slideIntoContainer( towards = AnimatedContentTransitionScope.SlideDirection.Right, animationSpec = tween(durationMillis = 350), @@ -51,7 +51,7 @@ fun NavGraphBuilder.postsRoute( }, exitTransition = { - when (targetState.destination.route) { + when (targetState.destination.id) { routeOf() -> slideOutOfContainer( towards = AnimatedContentTransitionScope.SlideDirection.Right, animationSpec = tween(durationMillis = 350), @@ -60,7 +60,7 @@ fun NavGraphBuilder.postsRoute( else -> null } }, - ) { + ) { entry -> val bottomSheetNavigator = LocalBottomSheetNavigator.current val isRouteFirstEntry = remember { @@ -68,7 +68,7 @@ fun NavGraphBuilder.postsRoute( mainNavController.currentBackStack.value.size == 3 } - val args = rememberNavArgsOf() + val args = entry.toRoute() LaunchedEffect(key1 = args.tags) { onCurrentTagsChange(args.tags) @@ -102,7 +102,7 @@ fun NavGraphBuilder.postsBottomRoute( mainNavController: NavHostController, onNavigatedBackByGesture: (Boolean) -> Unit, ) { - composable { + composable(PostNavType) { val lambdaOnDownload = LocalLambdaOnDownload.current val bottomSheetNavigator = LocalBottomSheetNavigator.current @@ -131,7 +131,7 @@ fun NavGraphBuilder.postsBottomRoute( ) } - composable { + composable(PostNavType) { val bottomSheetNavigator = LocalBottomSheetNavigator.current val lambdaOnShare = LocalLambdaOnShare.current diff --git a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/more/PostMoreViewModel.kt b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/more/PostMoreViewModel.kt index 590f70b9..9c594d22 100644 --- a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/more/PostMoreViewModel.kt +++ b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/more/PostMoreViewModel.kt @@ -2,20 +2,21 @@ package com.uragiristereo.mikansei.feature.home.posts.more import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Profile import com.uragiristereo.mikansei.core.domain.module.database.UserRepository import com.uragiristereo.mikansei.core.model.danbooru.Post import com.uragiristereo.mikansei.core.product.shared.postfavoritevote.PostFavoriteVote import com.uragiristereo.mikansei.core.product.shared.postfavoritevote.PostFavoriteVoteImpl import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import kotlinx.coroutines.flow.StateFlow class PostMoreViewModel( savedStateHandle: SavedStateHandle, private val userRepository: UserRepository, ) : ViewModel(), PostFavoriteVote by PostFavoriteVoteImpl() { - override val post: Post = savedStateHandle.navArgsOf()!!.post + override val post: Post = savedStateHandle.toRoute(PostNavType).post val activeUser: StateFlow get() = userRepository.active diff --git a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/share/ShareViewModel.kt b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/share/ShareViewModel.kt index fe0b941e..f14556bc 100644 --- a/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/share/ShareViewModel.kt +++ b/feature/home/posts/src/main/java/com/uragiristereo/mikansei/feature/home/posts/share/ShareViewModel.kt @@ -6,12 +6,13 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.module.network.NetworkRepository import com.uragiristereo.mikansei.core.domain.usecase.ConvertFileSizeUseCase import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import kotlinx.coroutines.launch class ShareViewModel( @@ -20,7 +21,7 @@ class ShareViewModel( private val convertFileSizeUseCase: ConvertFileSizeUseCase, danbooruRepository: DanbooruRepository, ) : ViewModel() { - val navArgs = checkNotNull(savedStateHandle.navArgsOf()) + val navArgs = savedStateHandle.toRoute(PostNavType) val postLink = danbooruRepository.host.parsePostLink(navArgs.post.id) diff --git a/feature/home/src/main/java/com/uragiristereo/mikansei/feature/home/HomeNavigation.kt b/feature/home/src/main/java/com/uragiristereo/mikansei/feature/home/HomeNavigation.kt index 4d60801e..de8113d9 100644 --- a/feature/home/src/main/java/com/uragiristereo/mikansei/feature/home/HomeNavigation.kt +++ b/feature/home/src/main/java/com/uragiristereo/mikansei/feature/home/HomeNavigation.kt @@ -5,34 +5,33 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.navigation import com.uragiristereo.mikansei.core.ui.animation.holdIn import com.uragiristereo.mikansei.core.ui.animation.holdOut import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.HomeRoutesString import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.feature.home.favorites.favoritesRoute import com.uragiristereo.mikansei.feature.home.more.core.moreRoute import com.uragiristereo.mikansei.feature.home.posts.core.postsRoute -import com.uragiristereo.serializednavigationextension.navigation.compose.navigation -import com.uragiristereo.serializednavigationextension.runtime.routeOf fun NavGraphBuilder.homeGraph( navController: NavHostController, onNavigatedBackByGesture: (Boolean) -> Unit, onCurrentTagsChange: (String) -> Unit, ) { - navigation( - startDestination = HomeRoute.Posts::class, - route = MainRoute.Home::class, + navigation( + startDestination = HomeRoute.Posts(), enterTransition = { - when (initialState.destination.route) { + when (initialState.destination.id) { in HomeRoutesString -> fadeIn(animationSpec = tween(durationMillis = 300)) routeOf() -> holdIn() else -> null } }, exitTransition = { - when (targetState.destination.route) { + when (targetState.destination.id) { in HomeRoutesString -> fadeOut(animationSpec = tween(durationMillis = 300)) routeOf() -> holdOut() routeOf() -> holdOut() @@ -40,7 +39,7 @@ fun NavGraphBuilder.homeGraph( } }, popEnterTransition = { - when (initialState.destination.route) { + when (initialState.destination.id) { in HomeRoutesString -> fadeIn(animationSpec = tween(durationMillis = 300)) routeOf() -> fadeIn() routeOf() -> holdIn() @@ -48,7 +47,7 @@ fun NavGraphBuilder.homeGraph( } }, popExitTransition = { - when (targetState.destination.route) { + when (targetState.destination.id) { in HomeRoutesString -> fadeOut(animationSpec = tween(durationMillis = 300)) routeOf() -> holdOut() routeOf() -> holdOut() diff --git a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ImageScreen.kt b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ImageScreen.kt index 7dcbed90..513360a2 100644 --- a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ImageScreen.kt +++ b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ImageScreen.kt @@ -28,7 +28,6 @@ import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.feature.image.image.ImagePost import com.uragiristereo.mikansei.feature.image.more.MoreBottomSheet import com.uragiristereo.mikansei.feature.image.video.VideoPost -import com.uragiristereo.serializednavigationextension.runtime.navigate import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel diff --git a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ViewerViewModel.kt b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ViewerViewModel.kt index 16874e2a..66a610b0 100644 --- a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ViewerViewModel.kt +++ b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/ViewerViewModel.kt @@ -5,13 +5,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType class ViewerViewModel( savedStateHandle: SavedStateHandle, ) : ViewModel() { - val post = checkNotNull(savedStateHandle.navArgsOf()).post + val post = savedStateHandle.toRoute(PostNavType).post var areAppBarsVisible by mutableStateOf(true) private set diff --git a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/core/ImageNavigation.kt b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/core/ImageNavigation.kt index 02cdb7ef..4ea9394a 100644 --- a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/core/ImageNavigation.kt +++ b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/core/ImageNavigation.kt @@ -4,14 +4,14 @@ import androidx.compose.animation.fadeOut import androidx.compose.runtime.State import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.animation.translateYFadeIn import com.uragiristereo.mikansei.core.ui.animation.translateYFadeOut import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import com.uragiristereo.mikansei.feature.image.ImageScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate fun NavGraphBuilder.imageRoute( navController: NavHostController, @@ -19,6 +19,7 @@ fun NavGraphBuilder.imageRoute( onNavigatedBackByGesture: (Boolean) -> Unit, ) { composable( + typeMap = PostNavType, enterTransition = { translateYFadeIn( initialOffsetY = { it / 5 }, diff --git a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/image/ImageViewModel.kt b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/image/ImageViewModel.kt index 40e2ae81..2bbffa4e 100644 --- a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/image/ImageViewModel.kt +++ b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/image/ImageViewModel.kt @@ -7,19 +7,20 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Profile import com.uragiristereo.mikansei.core.domain.module.database.UserRepository import com.uragiristereo.mikansei.core.model.preferences.user.DetailSizePreference import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import com.uragiristereo.mikansei.feature.image.image.core.ImageLoadingState -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf import kotlinx.coroutines.flow.StateFlow class ImageViewModel( savedStateHandle: SavedStateHandle, private val userRepository: UserRepository, ) : ViewModel() { - val post = checkNotNull(savedStateHandle.navArgsOf()).post + val post = savedStateHandle.toRoute(PostNavType).post val activeUser: StateFlow get() = userRepository.active diff --git a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/more/MoreBottomSheetViewModel.kt b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/more/MoreBottomSheetViewModel.kt index 09aac613..7c2c30f3 100644 --- a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/more/MoreBottomSheetViewModel.kt +++ b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/more/MoreBottomSheetViewModel.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Tag import com.uragiristereo.mikansei.core.domain.module.database.TagCategoryRepository @@ -27,7 +28,7 @@ import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.product.shared.postfavoritevote.PostFavoriteVote import com.uragiristereo.mikansei.core.product.shared.postfavoritevote.PostFavoriteVoteImpl import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import kotlinx.coroutines.launch import timber.log.Timber @@ -41,7 +42,7 @@ class MoreBottomSheetViewModel( private val convertFileSizeUseCase: ConvertFileSizeUseCase, ) : ViewModel(), PostFavoriteVote by PostFavoriteVoteImpl() { - override var post = savedStateHandle.navArgsOf()!!.post + override var post = savedStateHandle.toRoute(PostNavType).post var infoExpanded by mutableStateOf(false) var tagsExpanded by mutableStateOf(false) diff --git a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/video/VideoViewModel.kt b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/video/VideoViewModel.kt index cff20b57..9fbaa779 100644 --- a/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/video/VideoViewModel.kt +++ b/feature/image/src/main/java/com/uragiristereo/mikansei/feature/image/video/VideoViewModel.kt @@ -15,10 +15,11 @@ import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.source.ProgressiveMediaSource +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.network.NetworkRepository import com.uragiristereo.mikansei.core.model.danbooru.Post import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf +import com.uragiristereo.mikansei.core.ui.navigation.PostNavType import kotlin.math.floor @androidx.annotation.OptIn(UnstableApi::class) @@ -27,7 +28,7 @@ class VideoViewModel( private val networkRepository: NetworkRepository, private val applicationContext: Context, ) : ViewModel() { - val post = checkNotNull(savedStateHandle.navArgsOf()).post + val post = savedStateHandle.toRoute(PostNavType).post val exoPlayer = buildExoPlayer() diff --git a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt index 3eb3c635..9a75eb9f 100644 --- a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt +++ b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt @@ -3,19 +3,20 @@ package com.uragiristereo.mikansei.feature.saved_searches import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController -import com.uragiristereo.mikansei.core.ui.extension.rememberParentViewModelStoreOwner +import androidx.navigation.compose.composable +import androidx.navigation.compose.navigation +import androidx.navigation.toRoute +import com.uragiristereo.mikansei.core.ui.extension.rememberParentNavBackStackEntry import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute +import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchTypes import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchesRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.feature.saved_searches.delete.DeleteSavedSearchContent import com.uragiristereo.mikansei.feature.saved_searches.list.SavedSearchesListItemActions import com.uragiristereo.mikansei.feature.saved_searches.new_or_edit.NewOrEditSavedSearchScreen import com.uragiristereo.mikansei.feature.saved_searches.new_or_edit.NewOrEditSavedSearchViewModel -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate -import com.uragiristereo.serializednavigationextension.runtime.navigation -import com.uragiristereo.serializednavigationextension.runtime.routeOf import org.koin.androidx.compose.defaultExtras import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.dsl.viewModelOf @@ -27,16 +28,10 @@ val savedSearchesModule = module { } fun NavGraphBuilder.savedSearchesGraph(navController: NavHostController) { - navigation( - startDestination = SavedSearchesRoute.Index::class, - route = MainRoute.SavedSearches::class, - ) { + navigation(startDestination = SavedSearchesRoute.Index) { composable { val bottomSheetNavigator = LocalBottomSheetNavigator.current - val parentViewModelStoreOwner = rememberParentViewModelStoreOwner( - navController = navController, - parentRoute = routeOf(), - ) + val parentViewModelStoreOwner = navController.rememberParentNavBackStackEntry() SavedSearchesScreen( viewModel = koinViewModel( @@ -84,12 +79,8 @@ fun NavGraphBuilder.savedSearchesGraph(navController: NavHostController) { ) } - composable { - val parentViewModelStoreOwner = rememberParentViewModelStoreOwner( - navController = navController, - parentRoute = routeOf(), - ) - + composable(SavedSearchTypes) { + val parentViewModelStoreOwner = navController.rememberParentNavBackStackEntry() val savedSearchesViewModel: SavedSearchesViewModel = koinViewModel( viewModelStoreOwner = parentViewModelStoreOwner, ) @@ -103,26 +94,21 @@ fun NavGraphBuilder.savedSearchesGraph(navController: NavHostController) { } fun NavGraphBuilder.savedSearchesBottomRoute(navController: NavHostController) { - composable { + composable(SavedSearchTypes) { entry -> val bottomSheetNavigator = LocalBottomSheetNavigator.current - val parentViewModelStoreOwner = rememberParentViewModelStoreOwner( - navController = navController, - parentRoute = routeOf(), - ) + val parentViewModelStoreOwner = navController.rememberParentNavBackStackEntry() val savedSearchesViewModel: SavedSearchesViewModel = koinViewModel( viewModelStoreOwner = parentViewModelStoreOwner, ) - val args = rememberNavArgsOf() + val args = entry.toRoute() - if (args != null) { - DeleteSavedSearchContent( - savedSearch = args.savedSearch, - onDeleteClick = { - bottomSheetNavigator.runHiding { - savedSearchesViewModel.deleteSavedSearch(id = args.savedSearch.id) - } - }, - ) - } + DeleteSavedSearchContent( + savedSearch = args.savedSearch, + onDeleteClick = { + bottomSheetNavigator.runHiding { + savedSearchesViewModel.deleteSavedSearch(id = args.savedSearch.id) + } + }, + ) } } diff --git a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt index ceeb433e..ce92782d 100644 --- a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt +++ b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt @@ -11,13 +11,14 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi import androidx.lifecycle.viewmodel.compose.saveable +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.SavedSearch import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.extension.strip +import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchTypes import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchesRoute import com.uragiristereo.mikansei.feature.saved_searches.new_or_edit.core.FabState -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch @@ -28,9 +29,7 @@ class NewOrEditSavedSearchViewModel( savedStateHandle: SavedStateHandle, private val danbooruRepository: DanbooruRepository, ) : ViewModel() { - private val navArgs = checkNotNull( - savedStateHandle.navArgsOf() - ) + private val navArgs = savedStateHandle.toRoute(SavedSearchTypes) val savedSearchId = navArgs.savedSearch?.id val shouldFocusToLabelsTextField = navArgs.query != null private val defaultQuery = navArgs.query ?: navArgs.savedSearch?.query ?: "" diff --git a/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/SearchViewModel.kt b/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/SearchViewModel.kt index 069c9be9..de758772 100644 --- a/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/SearchViewModel.kt +++ b/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/SearchViewModel.kt @@ -13,6 +13,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi import androidx.lifecycle.viewmodel.compose.saveable +import androidx.navigation.toRoute import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Tag import com.uragiristereo.mikansei.core.domain.module.database.TagCategoryRepository import com.uragiristereo.mikansei.core.domain.module.search.BrowseChipType @@ -22,7 +23,6 @@ import com.uragiristereo.mikansei.core.domain.usecase.GetTagsUseCase import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.navigation.MainRoute import com.uragiristereo.mikansei.feature.search.state.SearchWordIndex -import com.uragiristereo.serializednavigationextension.runtime.navArgsOf import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -46,7 +46,7 @@ class SearchViewModel( private val generateChipsFromTagsUseCase: GenerateChipsFromTagsUseCase, private val getTagsUseCase: GetTagsUseCase, ) : ViewModel() { - private val tags = savedStateHandle.navArgsOf(MainRoute.Search()).tags + private val tags = savedStateHandle.toRoute().tags var query by savedStateHandle.saveable(stateSaver = TextFieldValue.Saver) { mutableStateOf( diff --git a/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/core/SearchNavigation.kt b/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/core/SearchNavigation.kt index 0bdea15a..e214db44 100644 --- a/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/core/SearchNavigation.kt +++ b/feature/search/src/main/java/com/uragiristereo/mikansei/feature/search/core/SearchNavigation.kt @@ -4,24 +4,22 @@ import androidx.compose.animation.fadeOut import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.animation.holdIn import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.HomeRoutesString import com.uragiristereo.mikansei.core.ui.navigation.MainRoute import com.uragiristereo.mikansei.feature.search.SearchScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate fun NavGraphBuilder.searchRoute( navController: NavHostController, ) { - composable( - defaultValue = MainRoute.Search(), + composable( enterTransition = { holdIn() }, exitTransition = { - when (targetState.destination.route) { + when (targetState.destination.id) { in HomeRoutesString -> fadeOut() else -> null } @@ -30,7 +28,7 @@ fun NavGraphBuilder.searchRoute( null }, popExitTransition = { - when (targetState.destination.route) { + when (targetState.destination.id) { in HomeRoutesString -> fadeOut() else -> null } diff --git a/feature/settings/src/main/java/com/uragiristereo/mikansei/feature/settings/core/SettingsNavigation.kt b/feature/settings/src/main/java/com/uragiristereo/mikansei/feature/settings/core/SettingsNavigation.kt index 425b22b6..bca84da7 100644 --- a/feature/settings/src/main/java/com/uragiristereo/mikansei/feature/settings/core/SettingsNavigation.kt +++ b/feature/settings/src/main/java/com/uragiristereo/mikansei/feature/settings/core/SettingsNavigation.kt @@ -2,19 +2,16 @@ package com.uragiristereo.mikansei.feature.settings.core import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.compose.navigation import com.uragiristereo.mikansei.core.ui.navigation.MainRoute import com.uragiristereo.mikansei.core.ui.navigation.SettingsRoute import com.uragiristereo.mikansei.feature.settings.SettingsScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigation fun NavGraphBuilder.settingsGraph( navController: NavHostController, ) { - navigation( - startDestination = SettingsRoute.Index::class, - route = MainRoute.Settings::class, - ) { + navigation(startDestination = SettingsRoute.Index) { composable { SettingsScreen( onNavigateBack = navController::navigateUp, diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt index fb182f3c..a24b9804 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/UserDeactivationScreen.kt @@ -19,10 +19,10 @@ import androidx.navigation.compose.rememberNavController import com.google.accompanist.insets.ui.Scaffold import com.uragiristereo.mikansei.core.product.component.ProductNavigationBarSpacer import com.uragiristereo.mikansei.core.ui.LocalScaffoldState +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.feature.user.deactivation.core.UserDeactivationTopAppBar import com.uragiristereo.mikansei.feature.user.deactivation.navigation.UserDeactivationNavGraph import com.uragiristereo.mikansei.feature.user.deactivation.navigation.UserDeactivationRoute -import com.uragiristereo.serializednavigationextension.runtime.routeOf import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel @@ -37,7 +37,7 @@ fun UserDeactivationScreen( val activeUser by viewModel.activeUser.collectAsState() val navController = rememberNavController() val currentBackStackEntry by navController.currentBackStackEntryAsState() - val currentRoute = currentBackStackEntry?.destination?.route + val currentRoute = currentBackStackEntry?.destination?.id val currentPage = when (currentRoute) { routeOf() -> UserDeactivationRoute.Agreement diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationNavigation.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationNavigation.kt index 47d94ef8..469ca990 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationNavigation.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/core/UserDeactivationNavigation.kt @@ -2,12 +2,11 @@ package com.uragiristereo.mikansei.feature.user.deactivation.core import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.UserRoute +import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.feature.user.deactivation.UserDeactivationScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate -import com.uragiristereo.serializednavigationextension.runtime.routeOf fun NavGraphBuilder.userDeactivationRoute( navController: NavHostController, diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt index 159b7a0a..56a8a7b8 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationNavGraph.kt @@ -14,6 +14,8 @@ import androidx.lifecycle.ViewModelStoreOwner import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.animation.translateXFadeIn import com.uragiristereo.mikansei.core.ui.animation.translateXFadeOut import com.uragiristereo.mikansei.feature.user.deactivation.UserDeactivationViewModel @@ -22,9 +24,6 @@ import com.uragiristereo.mikansei.feature.user.deactivation.in_app.UserDeactivat import com.uragiristereo.mikansei.feature.user.deactivation.in_app.UserDeactivationInAppScreen import com.uragiristereo.mikansei.feature.user.deactivation.in_web.UserDeactivationInWebScreen import com.uragiristereo.mikansei.feature.user.deactivation.methods.UserDeactivationMethodsScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.NavHost -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate import org.koin.androidx.compose.koinViewModel @Composable @@ -64,7 +63,7 @@ private fun NavGraphBuilder.agreementRoute( innerPadding: PaddingValues, parentViewModelStoreOwner: ViewModelStoreOwner, ) { - composable(UserDeactivationRoute.Agreement) { + composable { val viewModel = koinViewModel( viewModelStoreOwner = parentViewModelStoreOwner, ) @@ -89,7 +88,7 @@ private fun NavGraphBuilder.methodsRoute( navController: NavHostController, innerPadding: PaddingValues, ) { - composable(UserDeactivationRoute.Methods) { + composable { UserDeactivationMethodsScreen( innerPadding = innerPadding, onInAppClick = { @@ -106,7 +105,7 @@ private fun NavGraphBuilder.inAppRoute( innerPadding: PaddingValues, parentViewModelStoreOwner: ViewModelStoreOwner, ) { - composable(UserDeactivationRoute.InApp) { + composable { val viewModel = koinViewModel( viewModelStoreOwner = parentViewModelStoreOwner, ) @@ -143,7 +142,7 @@ private fun NavGraphBuilder.inWebRoute( innerPadding: PaddingValues, parentViewModelStoreOwner: ViewModelStoreOwner, ) { - composable(UserDeactivationRoute.InWeb) { + composable { val context = LocalContext.current val viewModel = koinViewModel( diff --git a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt index 19bfef9a..6b251885 100644 --- a/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt +++ b/feature/user/deactivation/src/main/java/com/uragiristereo/mikansei/feature/user/deactivation/navigation/UserDeactivationRoute.kt @@ -1,6 +1,6 @@ package com.uragiristereo.mikansei.feature.user.deactivation.navigation -import com.uragiristereo.serializednavigationextension.runtime.NavRoute +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute import kotlinx.serialization.Serializable sealed interface UserDeactivationRoute : NavRoute { diff --git a/feature/user/delegation/src/main/java/com/uragiristereo/mikansei/feature/user/delegation/core/UserDelegationSettingsNavigation.kt b/feature/user/delegation/src/main/java/com/uragiristereo/mikansei/feature/user/delegation/core/UserDelegationSettingsNavigation.kt index 05c7b732..829f1b4f 100644 --- a/feature/user/delegation/src/main/java/com/uragiristereo/mikansei/feature/user/delegation/core/UserDelegationSettingsNavigation.kt +++ b/feature/user/delegation/src/main/java/com/uragiristereo/mikansei/feature/user/delegation/core/UserDelegationSettingsNavigation.kt @@ -2,9 +2,9 @@ package com.uragiristereo.mikansei.feature.user.delegation.core import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.user.delegation.UserDelegationSettingsScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable fun NavGraphBuilder.userDelegationSettingsRoute(navController: NavHostController) { composable { diff --git a/feature/user/login/src/main/java/com/uragiristereo/mikansei/feature/user/login/core/LoginNavigation.kt b/feature/user/login/src/main/java/com/uragiristereo/mikansei/feature/user/login/core/LoginNavigation.kt index 04b87189..03285c5f 100644 --- a/feature/user/login/src/main/java/com/uragiristereo/mikansei/feature/user/login/core/LoginNavigation.kt +++ b/feature/user/login/src/main/java/com/uragiristereo/mikansei/feature/user/login/core/LoginNavigation.kt @@ -2,9 +2,9 @@ package com.uragiristereo.mikansei.feature.user.login.core import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.user.login.LoginScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable fun NavGraphBuilder.loginRoute( navController: NavHostController, diff --git a/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/ManageUserScreen.kt b/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/ManageUserScreen.kt index dbddc24b..0b6064bb 100644 --- a/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/ManageUserScreen.kt +++ b/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/ManageUserScreen.kt @@ -30,9 +30,9 @@ import com.uragiristereo.mikansei.core.resources.R import com.uragiristereo.mikansei.core.ui.LocalScaffoldState import com.uragiristereo.mikansei.core.ui.composable.SectionTitle import com.uragiristereo.mikansei.core.ui.extension.plus +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.user.manage.core.ProfileItem -import com.uragiristereo.serializednavigationextension.runtime.NavRoute import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalFoundationApi::class) diff --git a/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/core/ManageNavigation.kt b/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/core/ManageNavigation.kt index fd71bc56..1b7f6975 100644 --- a/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/core/ManageNavigation.kt +++ b/feature/user/manage/src/main/java/com/uragiristereo/mikansei/feature/user/manage/core/ManageNavigation.kt @@ -3,12 +3,11 @@ package com.uragiristereo.mikansei.feature.user.manage.core import androidx.compose.material.ExperimentalMaterialApi import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.user.manage.ManageUserScreen import com.uragiristereo.mikansei.feature.user.manage.switch_account.SwitchAccountContent -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate fun NavGraphBuilder.manageRoute( navController: NavHostController, diff --git a/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/UserSettingsScreen.kt b/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/UserSettingsScreen.kt index 159c0ec5..73c398cf 100644 --- a/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/UserSettingsScreen.kt +++ b/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/UserSettingsScreen.kt @@ -47,9 +47,9 @@ import com.uragiristereo.mikansei.core.ui.composable.Scaffold2 import com.uragiristereo.mikansei.core.ui.composable.SettingTip import com.uragiristereo.mikansei.core.ui.extension.alphabet import com.uragiristereo.mikansei.core.ui.extension.forEach +import com.uragiristereo.mikansei.core.ui.navigation.NavRoute import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.user.settings.core.UserSettingsTopAppBar -import com.uragiristereo.serializednavigationextension.runtime.NavRoute import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel diff --git a/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/core/UserSettingsNavigation.kt b/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/core/UserSettingsNavigation.kt index 49657087..77e5b4c7 100644 --- a/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/core/UserSettingsNavigation.kt +++ b/feature/user/settings/src/main/java/com/uragiristereo/mikansei/feature/user/settings/core/UserSettingsNavigation.kt @@ -2,10 +2,9 @@ package com.uragiristereo.mikansei.feature.user.settings.core import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.composable import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.user.settings.UserSettingsScreen -import com.uragiristereo.serializednavigationextension.navigation.compose.composable -import com.uragiristereo.serializednavigationextension.runtime.navigate fun NavGraphBuilder.userSettingsRoute( navController: NavHostController, diff --git a/feature/user/src/main/java/com/uragiristereo/mikansei/feature/user/UserNavigation.kt b/feature/user/src/main/java/com/uragiristereo/mikansei/feature/user/UserNavigation.kt index e436bc56..e9e6d535 100644 --- a/feature/user/src/main/java/com/uragiristereo/mikansei/feature/user/UserNavigation.kt +++ b/feature/user/src/main/java/com/uragiristereo/mikansei/feature/user/UserNavigation.kt @@ -2,6 +2,7 @@ package com.uragiristereo.mikansei.feature.user import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController +import androidx.navigation.compose.navigation import com.uragiristereo.mikansei.core.ui.navigation.MainRoute import com.uragiristereo.mikansei.core.ui.navigation.UserRoute import com.uragiristereo.mikansei.feature.user.deactivation.core.userDeactivationRoute @@ -9,15 +10,11 @@ import com.uragiristereo.mikansei.feature.user.delegation.core.userDelegationSet import com.uragiristereo.mikansei.feature.user.login.core.loginRoute import com.uragiristereo.mikansei.feature.user.manage.core.manageRoute import com.uragiristereo.mikansei.feature.user.settings.core.userSettingsRoute -import com.uragiristereo.serializednavigationextension.runtime.navigation fun NavGraphBuilder.userGraph( navController: NavHostController, ) { - navigation( - startDestination = UserRoute.Login::class, - route = MainRoute.User::class, - ) { + navigation(startDestination = UserRoute.Login::class) { loginRoute(navController) manageRoute(navController) From c1097096b51f3e69f0dd2574e950fa015844f857 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sun, 12 Jan 2025 01:51:45 +0700 Subject: [PATCH 08/11] Main: Disable predictive back --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cdd7ae82..72970f44 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,7 +13,7 @@ android:name=".MikanseiApp" android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" - android:enableOnBackInvokedCallback="true" + android:enableOnBackInvokedCallback="false" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" From 4643004a5e7e54e1d490eae934f9680fb702af44 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sun, 12 Jan 2025 15:52:18 +0700 Subject: [PATCH 09/11] UI: Fix nullable type navigation arguments (1/2) --- .../mikansei/core/ui/navigation/HomeRoute.kt | 2 - .../core/ui/navigation/NavTypeMapOf.kt | 42 +++++++++++++++++++ .../core/ui/navigation/SavedSearchesRoute.kt | 4 +- .../core/ui/navigation/SerializableNavType.kt | 39 ----------------- 4 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavTypeMapOf.kt delete mode 100644 core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt index 4c3734af..3b51d904 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/HomeRoute.kt @@ -1,7 +1,6 @@ package com.uragiristereo.mikansei.core.ui.navigation import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.Favorite -import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.SavedSearch import com.uragiristereo.mikansei.core.model.danbooru.Post import kotlinx.serialization.Serializable @@ -60,4 +59,3 @@ val HomeRoutesString = listOf( val PostNavType = navTypeMapOf() val FavoriteNavType = navTypeMapOf() -val SavedSearchTypes = navTypeMapOf() diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavTypeMapOf.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavTypeMapOf.kt new file mode 100644 index 00000000..7637448a --- /dev/null +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/NavTypeMapOf.kt @@ -0,0 +1,42 @@ +package com.uragiristereo.mikansei.core.ui.navigation + +import android.net.Uri +import android.os.Bundle +import androidx.navigation.NavType +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +inline fun navTypeMapOf(): Map> { + val navType = object : NavType(isNullableAllowed = true) { + override fun get(bundle: Bundle, key: String): T? { + val encoded = bundle.getString(key) ?: return null + + return Json.decodeFromString(encoded) + } + + override fun parseValue(value: String): T { + return Json.decodeFromString(Uri.decode(value)) + } + + override fun put(bundle: Bundle, key: String, value: T?) { + if (value != null) { + bundle.putString(key, Json.encodeToString(value)) + } + } + + override fun serializeAsValue(value: T?): String { + if (value == null) { + return "null" + } + + return Uri.encode(Json.encodeToString(value)) + } + } + + return mapOf( + typeOf() to navType, + typeOf() to navType, + ) +} diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt index da202e02..07909302 100644 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt +++ b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SavedSearchesRoute.kt @@ -10,9 +10,11 @@ sealed interface SavedSearchesRoute : NavRoute { @Serializable data class NewOrEdit( val query: String?, - val savedSearch: SavedSearch?, + val savedSearch: SavedSearch? = null, ) : SavedSearchesRoute @Serializable data class Delete(val savedSearch: SavedSearch) : SavedSearchesRoute } + +val SavedSearchNavType = navTypeMapOf() diff --git a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt b/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt deleted file mode 100644 index 32e7f77e..00000000 --- a/core/ui/src/main/java/com/uragiristereo/mikansei/core/ui/navigation/SerializableNavType.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.uragiristereo.mikansei.core.ui.navigation - -import android.net.Uri -import android.os.Bundle -import androidx.navigation.NavType -import kotlinx.serialization.InternalSerializationApi -import kotlinx.serialization.json.Json -import kotlinx.serialization.serializer -import kotlin.reflect.KClass -import kotlin.reflect.KType -import kotlin.reflect.typeOf - -@OptIn(InternalSerializationApi::class) -abstract class SerializableNavType(private val klass: KClass) : NavType(true) { - override fun get(bundle: Bundle, key: String): T? { - return Json.decodeFromString(klass.serializer(), requireNotNull(bundle.getString(key))) - } - - override fun parseValue(value: String): T { - return Json.decodeFromString(klass.serializer(), Uri.decode(value)) - } - - override fun put(bundle: Bundle, key: String, value: T) { - bundle.putString(key, Json.encodeToString(klass.serializer(), value)) - } - - override fun serializeAsValue(value: T): String { - return Uri.encode(Json.encodeToString(klass.serializer(), value)) - } -} - -inline fun navTypeMapOf(): Map> { - val navType = object : SerializableNavType(T::class) {} - - return mapOf( - typeOf() to navType, - typeOf() to navType, - ) -} From ac7f55db35586f8ec924417d3a469ddee6142cbf Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Sun, 12 Jan 2025 15:53:02 +0700 Subject: [PATCH 10/11] Saved Searches: Fix nullable type navigation arguments (2/2) --- .../mikansei/feature/saved_searches/SavedSearchesModule.kt | 6 +++--- .../new_or_edit/NewOrEditSavedSearchViewModel.kt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt index 9a75eb9f..b8ac9caa 100644 --- a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt +++ b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/SavedSearchesModule.kt @@ -10,7 +10,7 @@ import com.uragiristereo.mikansei.core.ui.extension.rememberParentNavBackStackEn import com.uragiristereo.mikansei.core.ui.modalbottomsheet.navigator.LocalBottomSheetNavigator import com.uragiristereo.mikansei.core.ui.navigation.HomeRoute import com.uragiristereo.mikansei.core.ui.navigation.MainRoute -import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchTypes +import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchNavType import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchesRoute import com.uragiristereo.mikansei.core.ui.navigation.routeOf import com.uragiristereo.mikansei.feature.saved_searches.delete.DeleteSavedSearchContent @@ -79,7 +79,7 @@ fun NavGraphBuilder.savedSearchesGraph(navController: NavHostController) { ) } - composable(SavedSearchTypes) { + composable(SavedSearchNavType) { val parentViewModelStoreOwner = navController.rememberParentNavBackStackEntry() val savedSearchesViewModel: SavedSearchesViewModel = koinViewModel( viewModelStoreOwner = parentViewModelStoreOwner, @@ -94,7 +94,7 @@ fun NavGraphBuilder.savedSearchesGraph(navController: NavHostController) { } fun NavGraphBuilder.savedSearchesBottomRoute(navController: NavHostController) { - composable(SavedSearchTypes) { entry -> + composable(SavedSearchNavType) { entry -> val bottomSheetNavigator = LocalBottomSheetNavigator.current val parentViewModelStoreOwner = navController.rememberParentNavBackStackEntry() val savedSearchesViewModel: SavedSearchesViewModel = koinViewModel( diff --git a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt index ce92782d..6f19a752 100644 --- a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt +++ b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt @@ -16,7 +16,7 @@ import com.uragiristereo.mikansei.core.domain.module.danbooru.DanbooruRepository import com.uragiristereo.mikansei.core.domain.module.danbooru.entity.SavedSearch import com.uragiristereo.mikansei.core.model.result.Result import com.uragiristereo.mikansei.core.ui.extension.strip -import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchTypes +import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchNavType import com.uragiristereo.mikansei.core.ui.navigation.SavedSearchesRoute import com.uragiristereo.mikansei.feature.saved_searches.new_or_edit.core.FabState import kotlinx.coroutines.channels.Channel @@ -29,7 +29,7 @@ class NewOrEditSavedSearchViewModel( savedStateHandle: SavedStateHandle, private val danbooruRepository: DanbooruRepository, ) : ViewModel() { - private val navArgs = savedStateHandle.toRoute(SavedSearchTypes) + private val navArgs = savedStateHandle.toRoute(SavedSearchNavType) val savedSearchId = navArgs.savedSearch?.id val shouldFocusToLabelsTextField = navArgs.query != null private val defaultQuery = navArgs.query ?: navArgs.savedSearch?.query ?: "" From db1ebbea6b6c8aaad5def67c0f3f517e07d8da64 Mon Sep 17 00:00:00 2001 From: Agung Watanabe <52477630+uragiristereo@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:20:26 +0700 Subject: [PATCH 11/11] Saved Searches: Fix forbid exit logic --- .../saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt index 6f19a752..657008c4 100644 --- a/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt +++ b/feature/saved_searches/src/main/java/com/uragiristereo/mikansei/feature/saved_searches/new_or_edit/NewOrEditSavedSearchViewModel.kt @@ -68,7 +68,6 @@ class NewOrEditSavedSearchViewModel( val areLabelsEdited by derivedStateOf { labelsTextField.text.strip(splitter = " ") != spaceSeparatedLabels - || spaceSeparatedLabels == "" } val fabState by derivedStateOf {