From f82c893c811a6af0ad85edda1954ad73d4e5a610 Mon Sep 17 00:00:00 2001 From: stslex Date: Mon, 19 Aug 2024 22:16:34 +0300 Subject: [PATCH 1/3] init ui test for compose ui screen --- .../st.slex.csplashscreen/ComposeAndroid.kt | 1 + .../feature/home/ExampleInstrumentedTest.kt | 24 ----------- .../feature/home/HomeScreenTest.kt | 40 +++++++++++++++++++ 3 files changed, 41 insertions(+), 24 deletions(-) delete mode 100644 feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/ExampleInstrumentedTest.kt create mode 100644 feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/HomeScreenTest.kt diff --git a/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/ComposeAndroid.kt b/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/ComposeAndroid.kt index 30e62670..6882da76 100644 --- a/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/ComposeAndroid.kt +++ b/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/ComposeAndroid.kt @@ -26,6 +26,7 @@ internal fun Project.configureAndroidCompose( androidTestImplementation("androidx-compose-ui-test-junit4") implementationBundle("accompanist", "compose", "lifecycle") implementation("appcompat", "material", "koin-androidx-compose") + debugImplementation("androidx-compose-manifest") } extensions.configure(action = ::configureVkompose) diff --git a/feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/ExampleInstrumentedTest.kt b/feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/ExampleInstrumentedTest.kt deleted file mode 100644 index 521f4511..00000000 --- a/feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package st.slex.csplashscreen.feature.home - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.stslex.csplashscreen.feature.home.test", appContext.packageName) - } -} \ No newline at end of file diff --git a/feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/HomeScreenTest.kt b/feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/HomeScreenTest.kt new file mode 100644 index 00000000..06adb289 --- /dev/null +++ b/feature/home/src/androidTest/java/st/slex/csplashscreen/feature/home/HomeScreenTest.kt @@ -0,0 +1,40 @@ +package st.slex.csplashscreen.feature.home + +import androidx.compose.runtime.remember +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.paging.PagingData +import androidx.paging.compose.collectAsLazyPagingItems +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlinx.coroutines.flow.flowOf +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import st.slex.csplashscreen.core.collection.ui.model.CollectionModel +import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.feature.home.ui.MainScreen + +// todo initial test for HomeScreen +@RunWith(AndroidJUnit4::class) +class HomeScreenTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun mainScreenTest() { + val collectionsFlow = flowOf(PagingData.from(emptyList())) + val photosFlow = flowOf(PagingData.from(emptyList())) + composeTestRule.setContent { + val collections = remember { collectionsFlow }.collectAsLazyPagingItems() + val photos = remember { photosFlow }.collectAsLazyPagingItems() + MainScreen( + navToImage = {}, + navToProfile = {}, + navToCollection = {}, + collections = collections, + photos = photos + ) + } + + } +} \ No newline at end of file From 6019d6990370d10039eb75b7d69f8d95031d2f18 Mon Sep 17 00:00:00 2001 From: stslex Date: Mon, 19 Aug 2024 23:19:36 +0300 Subject: [PATCH 2/3] init new navigation method --- .../st/slex/csplashscreen/ui/InitialApp.kt | 14 +++-- .../csplashscreen/ui/InitialAppViewModel.kt | 11 +++- .../st/slex/csplashscreen/ui/MainActivity.kt | 4 +- .../ui/components/NavigationHost.kt | 6 +- .../bottom_appbar/BottomAppBarNavigation.kt | 11 ++-- .../bottom_appbar/BottomAppBarResource.kt | 15 ++--- build.gradle.kts | 2 +- .../st/slex/csplashscreen/core/core/Logger.kt | 4 +- core/navigation/build.gradle.kts | 5 +- .../core/navigation/AppArguments.kt | 34 ----------- .../core/navigation/AppDestination.kt | 51 ----------------- .../csplashscreen/core/navigation/Screen.kt | 48 ++++++++++++++++ .../core/navigation/di/NavigationModule.kt | 4 +- .../navigation/navigator/NavigationScreen.kt | 15 ----- .../navigation/navigator/NavigationTarget.kt | 57 +++---------------- .../core/navigation/navigator/Navigator.kt | 8 +-- .../navigation/navigator/NavigatorImpl.kt | 28 ++++----- .../navigation/navigator/NavigatorOptions.kt | 5 ++ .../core/ui/base/DaggerViewModel.kt | 23 +++----- .../slex/csplashscreen/core/ui/mvi/Store.kt | 4 +- .../navigation/SingleCollectionGraph.kt | 10 ++-- .../navigation/SingleCollectionRouterImpl.kt | 6 +- .../favourite/navigation/FavouriteGraph.kt | 9 ++- .../navigation/FavouriteRouterImpl.kt | 10 +++- .../feature/home/navigation/HomeGraph.kt | 6 +- .../feature/home/navigation/HomeRouterImpl.kt | 9 ++- .../navigation/ImageDetailGraph.kt | 14 ++--- .../navigation/ImageDetailRouterImpl.kt | 12 +++- .../ui/presenter/ImageDetailStore.kt | 6 +- .../ui/presenter/ImageDetailStoreComponent.kt | 26 +++------ .../search/navigation/SearchPhotosGraph.kt | 12 ++-- .../navigation/SearchPhotosRouterImpl.kt | 6 +- .../search/ui/presenter/SearchStore.kt | 4 +- .../ui/presenter/SearchStoreComponent.kt | 22 ++----- .../feature/user/navigation/UserGraph.kt | 18 +++--- .../feature/user/navigation/UserRouterImpl.kt | 11 ++-- .../feature/user/ui/presenter/UserStore.kt | 8 +-- .../user/ui/presenter/UserStoreComponent.kt | 6 +- gradle/libs.versions.toml | 12 ++-- 39 files changed, 227 insertions(+), 329 deletions(-) delete mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppArguments.kt delete mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppDestination.kt create mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt delete mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationScreen.kt create mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorOptions.kt diff --git a/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt b/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt index 28b1d264..f49f4d67 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt @@ -22,8 +22,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.google.accompanist.systemuicontroller.rememberSystemUiController -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget +import st.slex.csplashscreen.core.core.Logger +import st.slex.csplashscreen.core.navigation.Screen import st.slex.csplashscreen.ui.components.NavHostControllerHolder import st.slex.csplashscreen.ui.components.NavigationHost import st.slex.csplashscreen.ui.components.bottom_appbar.BottomAppBarResource @@ -34,18 +34,22 @@ import st.slex.csplashscreen.ui.components.bottom_appbar.MainBottomAppBar @Stable fun InitialApp( navControllerHolder: NavHostControllerHolder, - onBottomAppBarClick: (NavigationTarget.Screen) -> Unit, + onBottomAppBarClick: (Screen) -> Unit, modifier: Modifier = Modifier, ) { val systemUiController = rememberSystemUiController() val isDarkTheme = isSystemInDarkTheme() var currentDestination by remember { - mutableStateOf(AppDestination.HOME) + mutableStateOf(Screen.Home) } navControllerHolder.navController.addOnDestinationChangedListener { _, destination, _ -> - currentDestination = AppDestination.findByRoute(destination.route) + Logger.d("Destination: ${destination.route}") + // todo need reflection to get Screen by route + currentDestination = destination.route?.let { + Screen.getByRoute(it) + } } DisposableEffect(systemUiController, isDarkTheme) { diff --git a/app/src/main/java/st/slex/csplashscreen/ui/InitialAppViewModel.kt b/app/src/main/java/st/slex/csplashscreen/ui/InitialAppViewModel.kt index 97623dc0..df603a7a 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/InitialAppViewModel.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/InitialAppViewModel.kt @@ -1,14 +1,21 @@ package st.slex.csplashscreen.ui import androidx.lifecycle.ViewModel +import st.slex.csplashscreen.core.navigation.Screen import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget import st.slex.csplashscreen.core.navigation.navigator.Navigator +import st.slex.csplashscreen.core.navigation.navigator.NavigatorOptions class InitialAppViewModel( private val navigator: Navigator ) : ViewModel() { - fun navigate(screen: NavigationTarget.Screen) { - navigator.navigate(screen) + fun navigate(screen: Screen) { + navigator( + NavigationTarget.Screen( + screen = screen, + options = NavigatorOptions(isSingleTop = true) + ), + ) } } \ No newline at end of file diff --git a/app/src/main/java/st/slex/csplashscreen/ui/MainActivity.kt b/app/src/main/java/st/slex/csplashscreen/ui/MainActivity.kt index 42ae9b3f..bf5ae3b5 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/MainActivity.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/MainActivity.kt @@ -32,7 +32,9 @@ class MainActivity : ComponentActivity() { Need Research to find more efficient way */ navControllerHolder = navHostControllerHolder, onBottomAppBarClick = remember { - { viewModel.navigate(it) } + { screen -> + viewModel.navigate(screen) + } } ) } diff --git a/app/src/main/java/st/slex/csplashscreen/ui/components/NavigationHost.kt b/app/src/main/java/st/slex/csplashscreen/ui/components/NavigationHost.kt index 8f308b08..4fc3b569 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/components/NavigationHost.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/components/NavigationHost.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.Stable import androidx.compose.ui.Modifier import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost -import st.slex.csplashscreen.core.navigation.AppDestination +import st.slex.csplashscreen.core.navigation.Screen import st.slex.csplashscreen.feature.collection.navigation.singleCollectionGraph import st.slex.csplashscreen.feature.favourite.navigation.favouriteGraph import st.slex.csplashscreen.feature.feature_photo_detail.navigation.imageDetailGraph @@ -21,11 +21,11 @@ class NavHostControllerHolder(val navController: NavHostController) fun NavigationHost( holder: NavHostControllerHolder, modifier: Modifier = Modifier, - startDestination: AppDestination = AppDestination.HOME + startDestination: Screen = Screen.Home ) { NavHost( navController = holder.navController, - startDestination = startDestination.navigationRoute + startDestination = startDestination ) { homeGraph(modifier) userGraph(modifier) diff --git a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt index 7777c96b..c6892293 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt @@ -11,13 +11,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget +import st.slex.csplashscreen.core.navigation.Screen @Composable fun MainBottomAppBar( - onBottomAppBarClick: (NavigationTarget.Screen) -> Unit, - currentDestination: AppDestination? + onBottomAppBarClick: (Screen) -> Unit, + currentDestination: Screen? ) { NavigationBar( modifier = Modifier @@ -43,7 +42,7 @@ fun MainBottomAppBar( private fun RowScope.BottomAppBarItem( item: BottomAppBarResource, isSelected: Boolean, - onBottomAppBarClick: (NavigationTarget.Screen) -> Unit + onBottomAppBarClick: (Screen) -> Unit ) { NavigationBarItem( selected = isSelected, @@ -53,7 +52,7 @@ private fun RowScope.BottomAppBarItem( icon = { Icon( imageVector = item.getIcon(isSelected), - contentDescription = item.appDestination.name + contentDescription = item.screen.javaClass.simpleName ) }, label = { diff --git a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt index a3964bb8..93393099 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt @@ -9,34 +9,33 @@ import androidx.compose.material.icons.outlined.Home import androidx.compose.material.icons.outlined.Search import androidx.compose.ui.graphics.vector.ImageVector import st.slex.csplashscreen.R -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen +import st.slex.csplashscreen.core.navigation.Screen enum class BottomAppBarResource( val unselectedIcon: ImageVector, val selectedIcon: ImageVector, - val appDestination: AppDestination, + val appDestination: Screen, val titleResource: Int, val screen: Screen ) { FAVOURITE( unselectedIcon = Icons.Outlined.FavoriteBorder, selectedIcon = Icons.Filled.Favorite, - appDestination = AppDestination.FAVOURITE, + appDestination = Screen.Favourite, titleResource = R.string.nav_title_favourite, screen = Screen.Favourite ), HOME( unselectedIcon = Icons.Outlined.Home, selectedIcon = Icons.Filled.Home, - appDestination = AppDestination.HOME, + appDestination = Screen.Home, titleResource = R.string.nav_title_home, screen = Screen.Home ), SEARCH( unselectedIcon = Icons.Outlined.Search, selectedIcon = Icons.Filled.Search, - appDestination = AppDestination.SEARCH_PHOTOS, + appDestination = Screen.SearchPhotosScreen(" "), titleResource = R.string.nav_title_search, screen = Screen.SearchPhotosScreen(query = " ") ); @@ -45,8 +44,6 @@ enum class BottomAppBarResource( companion object { - fun isAppbar( - appDestination: AppDestination? - ): Boolean = entries.any { it.appDestination == appDestination } + fun isAppbar(screen: Any?): Boolean = entries.any { it.appDestination == screen } } } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index c4c90e15..01f2c5f0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ plugins { alias(libs.plugins.application) apply false alias(libs.plugins.kotlin) apply false alias(libs.plugins.library) apply false - alias(libs.plugins.serialization) + alias(libs.plugins.serialization) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.room) apply false alias(libs.plugins.vkompose) apply false diff --git a/core/core/src/main/java/st/slex/csplashscreen/core/core/Logger.kt b/core/core/src/main/java/st/slex/csplashscreen/core/core/Logger.kt index 25d343b9..ed84d48f 100644 --- a/core/core/src/main/java/st/slex/csplashscreen/core/core/Logger.kt +++ b/core/core/src/main/java/st/slex/csplashscreen/core/core/Logger.kt @@ -6,7 +6,7 @@ object Logger { private const val DEFAULT_TAG = "GALLERY" - fun exception( + fun e( throwable: Throwable, tag: String? = null, message: String? = null @@ -20,7 +20,7 @@ object Logger { ) } - fun debug( + fun d( message: String, tag: String? = null, ) { diff --git a/core/navigation/build.gradle.kts b/core/navigation/build.gradle.kts index 759e9ca0..b41a29fa 100644 --- a/core/navigation/build.gradle.kts +++ b/core/navigation/build.gradle.kts @@ -1,10 +1,13 @@ plugins { - id("csplashscreen.android.library") + alias(libs.plugins.convention.library) + alias(libs.plugins.convention.library.compose) + alias(libs.plugins.serialization) } dependencies { implementation(project(":core:core")) api(libs.androidx.compose.navigation) + implementation(libs.kotlinx.serialization.json) } android.namespace = "st.slex.csplashscreen.core.navigation" \ No newline at end of file diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppArguments.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppArguments.kt deleted file mode 100644 index 96c6124e..00000000 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppArguments.kt +++ /dev/null @@ -1,34 +0,0 @@ -package st.slex.csplashscreen.core.navigation - -sealed class AppArguments( - vararg val arguments: String -) { - - val argumentsForRoute: String - get() = when (arguments.isEmpty()) { - true -> String() - false -> arguments.joinToString(separator = "/", prefix = "/") - } - - data object Empty : AppArguments() - - data class ImageDetailScreen( - val imageId: String - ) : AppArguments(imageId) - - data class CollectionScreen( - val collectionId: String - ) : AppArguments(collectionId) - - data class SearchPhotosScreen( - private val query: String - ) : AppArguments(query) { - - val checkedQuery: String - get() = arguments.firstOrNull().orEmpty().trimEnd() - } - - data class UserScreen( - val username: String - ) : AppArguments(username) -} diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppDestination.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppDestination.kt deleted file mode 100644 index 9bf14ed4..00000000 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/AppDestination.kt +++ /dev/null @@ -1,51 +0,0 @@ -package st.slex.csplashscreen.core.navigation - -import androidx.navigation.NamedNavArgument -import androidx.navigation.NavBackStackEntry -import androidx.navigation.NavType -import androidx.navigation.navArgument - -enum class AppDestination( - private vararg val argsNames: String -) { - HOME, - IMAGE_DETAIL("imageId"), - COLLECTION("collection_id"), - SEARCH_PHOTOS("query"), - FAVOURITE, - USER("username"), - UNDEFINED; - - val destinationName: String = "${name}_route" - val navigationRoute: String = "$destinationName${argsNames.argumentsRoute}" - val composableArguments: List = argsNames.map { name -> - navArgument(name) { NavType.StringType } - } - - // TODO Arguments always String - Need research for Parcelable implementation - fun parseArguments( - navBackStackEntry: NavBackStackEntry - ): List = argsNames.map { name -> - navBackStackEntry.arguments?.getString(name).orEmpty() - } - - private val Array.argumentsRoute: String - get() = if (isEmpty()) "" else joinToString( - separator = "}/{", - prefix = "/{", - postfix = "}" - ) - - companion object { - - fun findByRoute( - route: String? - ) = if (route.isNullOrBlank()) { - UNDEFINED - } else { - AppDestination.entries.firstOrNull { - it.navigationRoute == route - } - } - } -} diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt new file mode 100644 index 00000000..b477239a --- /dev/null +++ b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt @@ -0,0 +1,48 @@ +package st.slex.csplashscreen.core.navigation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import androidx.navigation.toRoute +import kotlinx.serialization.Serializable + +@Serializable +@Stable +sealed interface Screen { + + @Serializable + data object Home : Screen + + @Serializable + data class ImageDetailScreen(val imageId: String) : Screen + + @Serializable + data class CollectionScreen(val collectionId: String) : Screen + + @Serializable + data class SearchPhotosScreen(val query: String) : Screen + + @Serializable + data class UserScreen(val username: String) : Screen + + @Serializable + data object Favourite : Screen + + + companion object { + fun getByRoute(route: String): Screen? = this::class.sealedSubclasses + .firstOrNull { screenClass -> + screenClass.simpleName.orEmpty() + .contains(route, ignoreCase = true) + }?.objectInstance as Screen? + } +} + +inline fun NavGraphBuilder.navScreen( + noinline content: @Composable (S) -> Unit +) { + composable { backStackEntry -> + content(backStackEntry.toRoute()) + } +} \ No newline at end of file diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationModule.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationModule.kt index a124a7a4..90eaedac 100644 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationModule.kt +++ b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationModule.kt @@ -6,7 +6,5 @@ import st.slex.csplashscreen.core.navigation.navigator.Navigator import st.slex.csplashscreen.core.navigation.navigator.NavigatorImpl fun moduleCoreNavigation(navController: NavHostController) = module { - single { - NavigatorImpl(navController) - } + single { NavigatorImpl(navController) } } \ No newline at end of file diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationScreen.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationScreen.kt deleted file mode 100644 index 4ff43115..00000000 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationScreen.kt +++ /dev/null @@ -1,15 +0,0 @@ -package st.slex.csplashscreen.core.navigation.navigator - -import st.slex.csplashscreen.core.navigation.AppArguments -import st.slex.csplashscreen.core.navigation.AppDestination - -interface NavigationScreen { - - val screen: AppDestination - - val isSingleTop: Boolean - get() = false - - val appArgs: AppArguments - get() = AppArguments.Empty -} \ No newline at end of file diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationTarget.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationTarget.kt index bb7656b3..043bcf50 100644 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationTarget.kt +++ b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigationTarget.kt @@ -1,56 +1,15 @@ package st.slex.csplashscreen.core.navigation.navigator -import st.slex.csplashscreen.core.navigation.AppArguments -import st.slex.csplashscreen.core.navigation.AppDestination +import kotlinx.serialization.Serializable +import st.slex.csplashscreen.core.navigation.Screen as AppScreen +@Serializable sealed interface NavigationTarget { data object PopBackStack : NavigationTarget - sealed interface Screen : NavigationTarget, NavigationScreen { - - val screenRoute: String - get() = "${screen.destinationName}${appArgs.argumentsForRoute}" - - data object Home : Screen { - override val screen: AppDestination = AppDestination.HOME - override val isSingleTop: Boolean = true - } - - data class ImageDetailScreen( - private val imageId: String - ) : Screen { - override val screen: AppDestination = AppDestination.IMAGE_DETAIL - override val appArgs: AppArguments.ImageDetailScreen = - AppArguments.ImageDetailScreen(imageId) - } - - data class CollectionScreen( - private val collectionId: String - ) : Screen { - override val screen: AppDestination = AppDestination.COLLECTION - override val appArgs: AppArguments = AppArguments.CollectionScreen(collectionId) - } - - data class SearchPhotosScreen( - private val query: String, - ) : Screen { - override val screen: AppDestination = AppDestination.SEARCH_PHOTOS - override val appArgs: AppArguments = AppArguments.SearchPhotosScreen(query) - override val isSingleTop: Boolean = true - } - - data class UserScreen( - private val username: String - ) : Screen { - override val screen: AppDestination = AppDestination.USER - override val appArgs: AppArguments = AppArguments.UserScreen(username) - } - - data object Favourite : Screen { - override val screen: AppDestination = AppDestination.FAVOURITE - override val appArgs: AppArguments = AppArguments.Empty - override val isSingleTop: Boolean = true - } - } -} \ No newline at end of file + data class Screen( + val screen: AppScreen, + val options: NavigatorOptions = NavigatorOptions() + ) : NavigationTarget +} diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/Navigator.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/Navigator.kt index 4fa774b4..ff1fbb28 100644 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/Navigator.kt +++ b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/Navigator.kt @@ -1,10 +1,6 @@ package st.slex.csplashscreen.core.navigation.navigator -import androidx.navigation.NavHostController - interface Navigator { - val controller: NavHostController - - fun navigate(screen: NavigationTarget) -} \ No newline at end of file + operator fun invoke(target: NavigationTarget) +} diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorImpl.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorImpl.kt index 34fd8723..9cf05f09 100644 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorImpl.kt +++ b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorImpl.kt @@ -4,26 +4,26 @@ import androidx.navigation.NavHostController import st.slex.csplashscreen.core.core.Logger class NavigatorImpl( - private val navController: NavHostController + private val navHostController: NavHostController ) : Navigator { - override val controller: NavHostController - get() = navController - - override fun navigate(screen: NavigationTarget) { - when (screen) { - is NavigationTarget.PopBackStack -> navController.popBackStack() - is NavigationTarget.Screen -> navigateScreen(screen) + override fun invoke(target: NavigationTarget) { + Logger.d("process $target", TAG) + when (target) { + NavigationTarget.PopBackStack -> popBackStack() + is NavigationTarget.Screen -> navigateScreen(target) } } - private fun navigateScreen(screen: NavigationTarget.Screen) { - val currentRoute = navController.currentDestination?.route ?: return - if (currentRoute == screen.screen.navigationRoute) return + private fun popBackStack() { + navHostController.popBackStack() + } + private fun navigateScreen(target: NavigationTarget.Screen) { + val currentRoute = navHostController.currentDestination?.route ?: return try { - navController.navigate(screen.screenRoute) { - if (screen.isSingleTop.not()) return@navigate + navHostController.navigate(target.screen) { + if (target.options.isSingleTop.not()) return@navigate popUpTo(currentRoute) { inclusive = true @@ -32,7 +32,7 @@ class NavigatorImpl( launchSingleTop = true } } catch (exception: Exception) { - Logger.exception(exception, TAG, "screen: $screen") + Logger.e(exception, TAG, "screen: ${target.screen}") } } diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorOptions.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorOptions.kt new file mode 100644 index 00000000..152c52e2 --- /dev/null +++ b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/navigator/NavigatorOptions.kt @@ -0,0 +1,5 @@ +package st.slex.csplashscreen.core.navigation.navigator + +data class NavigatorOptions( + val isSingleTop: Boolean = false, +) diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/DaggerViewModel.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/DaggerViewModel.kt index 59651c2c..2a91d585 100644 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/DaggerViewModel.kt +++ b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/DaggerViewModel.kt @@ -3,24 +3,19 @@ package st.slex.csplashscreen.core.ui.base import androidx.compose.runtime.Composable import androidx.lifecycle.ViewModel import androidx.navigation.NavGraphBuilder -import androidx.navigation.compose.composable import org.koin.androidx.compose.koinViewModel -import st.slex.csplashscreen.core.navigation.AppDestination +import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.navigation.navScreen -inline fun NavGraphBuilder.createScreen( - appDestination: AppDestination, - crossinline content: @Composable (VM, List) -> Unit +inline fun NavGraphBuilder.screen( + noinline content: @Composable (Destination, S) -> Unit ) { - composable( - route = appDestination.navigationRoute, - arguments = appDestination.composableArguments - ) { navBackStackEntry -> - val arguments = appDestination.parseArguments(navBackStackEntry) - val viewModel: VM = koinViewModel( - key = arguments.hashCode().toString() + navScreen { screen -> + val viewModel: S = koinViewModel( + key = screen.hashCode().toString() ) /*TODO maybe good point to make instance of state, event, action here and then send in to Content Screen*/ - content(viewModel, arguments) + content(screen, viewModel) } -} \ No newline at end of file +} diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Store.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Store.kt index d1865ca4..961d92cb 100644 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Store.kt +++ b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Store.kt @@ -91,7 +91,7 @@ abstract class Store( .onSuccess(onSuccess) .onFailure { error -> onFailure(error) - Logger.exception(error) + Logger.e(error) } } @@ -102,7 +102,7 @@ abstract class Store( .flowOn(appDispatcher.default) .catch { error -> onError(error) - Logger.exception(error) + Logger.e(error) } .onEach(each) .launchIn(viewModelScope) diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt index 1a84e6be..c80dcfaa 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt @@ -6,9 +6,8 @@ import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState -import st.slex.csplashscreen.core.navigation.AppArguments -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.ui.base.createScreen +import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.ui.base.screen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent import st.slex.csplashscreen.feature.collection.ui.CollectionScreen import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore @@ -17,12 +16,11 @@ import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionSto fun NavGraphBuilder.singleCollectionGraph( modifier: Modifier = Modifier, ) { - createScreen(AppDestination.COLLECTION) { store: SingleCollectionStore, args -> - val arguments = args.first().let(AppArguments::CollectionScreen) + screen { screen: Screen.CollectionScreen, store: SingleCollectionStore -> val photos = remember { store.state.mapState { it.photos } }.collectAsLazyPagingItems() LaunchedEffect(Unit) { - store.sendAction(Action.Init(arguments.collectionId)) + store.sendAction(Action.Init(screen.collectionId)) } store.event.CollectAsEvent { event -> diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouterImpl.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouterImpl.kt index f67e8dea..0f567c9d 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouterImpl.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouterImpl.kt @@ -1,5 +1,7 @@ package st.slex.csplashscreen.feature.collection.navigation +import st.slex.csplashscreen.core.navigation.Screen.ImageDetailScreen +import st.slex.csplashscreen.core.navigation.Screen.UserScreen import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.Navigation @@ -16,10 +18,10 @@ class SingleCollectionRouterImpl( } private fun navToImage(event: Navigation.ImageDetail) { - navigator.navigate(Screen.ImageDetailScreen(event.uuid)) + navigator(Screen(ImageDetailScreen(event.uuid))) } private fun navToProfile(event: Navigation.Profile) { - navigator.navigate(Screen.UserScreen(event.username)) + navigator(Screen(UserScreen(event.username))) } } \ No newline at end of file diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt index f704e73b..2d746c85 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt @@ -6,8 +6,8 @@ import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.ui.base.createScreen +import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.ui.base.screen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent import st.slex.csplashscreen.feature.favourite.ui.FavouriteScreen import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore @@ -16,9 +16,8 @@ import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreCompon fun NavGraphBuilder.favouriteGraph( modifier: Modifier = Modifier, ) { - createScreen( - appDestination = AppDestination.FAVOURITE, - ) { store: FavouriteStore, _ -> + + screen { _, store -> LaunchedEffect(Unit) { store.sendAction(Action.Init) diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouterImpl.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouterImpl.kt index 2bec3ecc..04c3fba5 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouterImpl.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouterImpl.kt @@ -1,7 +1,11 @@ package st.slex.csplashscreen.feature.favourite.navigation +import st.slex.csplashscreen.core.navigation.Screen.Home +import st.slex.csplashscreen.core.navigation.Screen.ImageDetailScreen +import st.slex.csplashscreen.core.navigation.Screen.UserScreen import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator +import st.slex.csplashscreen.core.navigation.navigator.NavigatorOptions import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.Navigation class FavouriteRouterImpl( @@ -17,14 +21,14 @@ class FavouriteRouterImpl( } private fun navToUser(event: Navigation.User) { - navigator.navigate(Screen.UserScreen(event.username)) + navigator(Screen(UserScreen(event.username))) } private fun navToImage(event: Navigation.Image) { - navigator.navigate(Screen.ImageDetailScreen(event.uuid)) + navigator(Screen(ImageDetailScreen(event.uuid))) } private fun navHome() { - navigator.navigate(Screen.Home) + navigator(Screen(Home, NavigatorOptions(isSingleTop = true))) } } \ No newline at end of file diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt index cac4508c..94c98ef9 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt @@ -6,8 +6,8 @@ import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.ui.base.createScreen +import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.ui.base.screen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent import st.slex.csplashscreen.feature.home.ui.MainScreen import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore @@ -16,7 +16,7 @@ import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.Action fun NavGraphBuilder.homeGraph( modifier: Modifier = Modifier, ) { - createScreen(AppDestination.HOME) { store: HomeStore, _ -> + screen { _, store -> LaunchedEffect(Unit) { store.sendAction(Action.Init) diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouterImpl.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouterImpl.kt index 9c5637c1..8e458ec8 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouterImpl.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouterImpl.kt @@ -1,5 +1,8 @@ package st.slex.csplashscreen.feature.home.navigation +import st.slex.csplashscreen.core.navigation.Screen.CollectionScreen +import st.slex.csplashscreen.core.navigation.Screen.ImageDetailScreen +import st.slex.csplashscreen.core.navigation.Screen.UserScreen import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.Navigation @@ -17,14 +20,14 @@ class HomeRouterImpl( } private fun navToProfile(event: Navigation.User) { - navigator.navigate(Screen.UserScreen(event.username)) + navigator(Screen(UserScreen(event.username))) } private fun navToImage(event: Navigation.Image) { - navigator.navigate(Screen.ImageDetailScreen(event.uuid)) + navigator(Screen(ImageDetailScreen(event.uuid))) } private fun navToCollection(event: Navigation.Collection) { - navigator.navigate(Screen.CollectionScreen(event.uuid)) + navigator(Screen(CollectionScreen(event.uuid))) } } \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailGraph.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailGraph.kt index f9f41a45..026ca1f8 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailGraph.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailGraph.kt @@ -13,9 +13,8 @@ import androidx.compose.ui.draw.blur import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.navigation.NavGraphBuilder -import st.slex.csplashscreen.core.navigation.AppArguments -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.ui.base.createScreen +import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.ui.base.screen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent import st.slex.csplashscreen.feature.feature_photo_detail.ui.ImageDetailScreen import st.slex.csplashscreen.feature.feature_photo_detail.ui.components.dialogs.DownloadImageDialog @@ -27,13 +26,10 @@ import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDeta fun NavGraphBuilder.imageDetailGraph( modifier: Modifier = Modifier, ) { - createScreen(AppDestination.IMAGE_DETAIL) { store: ImageDetailStore, args -> - val arguments = args.firstOrNull() - .orEmpty() - .let(AppArguments::ImageDetailScreen) + screen { screen, store -> - LaunchedEffect(arguments) { - store.sendAction(Action.Init(arguments)) + LaunchedEffect(screen) { + store.sendAction(Action.Init(screen)) } val state by remember { store.state }.collectAsState() diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouterImpl.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouterImpl.kt index 24aa598d..d3f52dad 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouterImpl.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouterImpl.kt @@ -1,7 +1,10 @@ package st.slex.csplashscreen.feature.feature_photo_detail.navigation +import st.slex.csplashscreen.core.navigation.Screen.SearchPhotosScreen +import st.slex.csplashscreen.core.navigation.Screen.UserScreen import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator +import st.slex.csplashscreen.core.navigation.navigator.NavigatorOptions import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Navigation class ImageDetailRouterImpl( @@ -16,10 +19,15 @@ class ImageDetailRouterImpl( } private fun navToSearch(event: Navigation.Search) { - navigator.navigate(Screen.SearchPhotosScreen(event.tag)) + navigator( + Screen( + screen = SearchPhotosScreen(event.tag), + options = NavigatorOptions(isSingleTop = true) + ) + ) } private fun navToProfile(event: Navigation.Profile) { - navigator.navigate(Screen.UserScreen(event.username)) + navigator(Screen(UserScreen(event.username))) } } \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt index 1927693a..2264982d 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt @@ -79,7 +79,7 @@ class ImageDetailStore( runCatching { interactor.like(action.imageDetail.photo) }.onFailure { error -> - Logger.exception(error) + Logger.e(error) } } } @@ -98,9 +98,9 @@ class ImageDetailStore( private fun actionInit(action: Action.Init) { updateState { currentState -> - currentState.copy(imageId = action.args.imageId) + currentState.copy(imageId = action.screen.imageId) } - interactor.getImageDetail(action.args.imageId) + interactor.getImageDetail(action.screen.imageId) .launch( onError = { error -> updateState { currentState -> diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStoreComponent.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStoreComponent.kt index 4fa12818..826dd2a8 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStoreComponent.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStoreComponent.kt @@ -1,7 +1,7 @@ package st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter import androidx.compose.runtime.Stable -import st.slex.csplashscreen.core.navigation.AppArguments +import st.slex.csplashscreen.core.navigation.Screen import st.slex.csplashscreen.core.ui.mvi.StoreComponent import st.slex.csplashscreen.feature.feature_photo_detail.domain.model.ImageDetail @@ -73,37 +73,25 @@ interface ImageDetailStoreComponent : StoreComponent { sealed interface Action : StoreComponent.Action { @Stable - data class Init( - val args: AppArguments.ImageDetailScreen - ) : Action + data class Init(val screen: Screen.ImageDetailScreen) : Action @Stable - data class SetWallpaperClick( - val url: String - ) : Action + data class SetWallpaperClick(val url: String) : Action @Stable - data class OnTagClick( - val tag: String - ) : Action + data class OnTagClick(val tag: String) : Action @Stable - data class OnProfileClick( - val username: String - ) : Action + data class OnProfileClick(val username: String) : Action @Stable - data class OnLikeClicked( - val imageDetail: ImageDetail - ) : Action + data class OnLikeClicked(val imageDetail: ImageDetail) : Action @Stable data object DownloadImageButtonClick : Action @Stable - data class DownloadImageChooseClick( - val type: DownloadImageType - ) : Action + data class DownloadImageChooseClick(val type: DownloadImageType) : Action @Stable data object CloseDialog : Action diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt index 695d2ff0..92b0a6de 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt @@ -8,9 +8,8 @@ import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState -import st.slex.csplashscreen.core.navigation.AppArguments -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.ui.base.createScreen +import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.ui.base.screen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent import st.slex.csplashscreen.feature.search.ui.SearchPhotosScreen import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore @@ -19,8 +18,7 @@ import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Ac fun NavGraphBuilder.searchPhotosGraph( modifier: Modifier = Modifier, ) { - createScreen(AppDestination.SEARCH_PHOTOS) { store: SearchStore, args -> - val arguments = args.firstOrNull().orEmpty().let(AppArguments::SearchPhotosScreen) + screen { screen, store -> val state by remember { store.state }.collectAsState() val photos = remember { @@ -30,8 +28,8 @@ fun NavGraphBuilder.searchPhotosGraph( store.state.mapState { it.historyItems } }.collectAsLazyPagingItems() - LaunchedEffect(arguments) { - store.sendAction(Action.Init(arguments)) + LaunchedEffect(screen) { + store.sendAction(Action.Init(screen)) } store.event.CollectAsEvent { event -> diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouterImpl.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouterImpl.kt index ee99eec7..c33327ff 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouterImpl.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouterImpl.kt @@ -1,5 +1,7 @@ package st.slex.csplashscreen.feature.search.navigation +import st.slex.csplashscreen.core.navigation.Screen.ImageDetailScreen +import st.slex.csplashscreen.core.navigation.Screen.UserScreen import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Navigation @@ -16,10 +18,10 @@ class SearchPhotosRouterImpl( } private fun navToImage(event: Navigation.ImageDetail) { - navigator.navigate(Screen.ImageDetailScreen(event.uuid)) + navigator(Screen(ImageDetailScreen(event.uuid))) } private fun navToProfile(event: Navigation.Profile) { - navigator.navigate(Screen.UserScreen(event.username)) + navigator(Screen(UserScreen(event.username))) } } \ No newline at end of file diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt index 47c9ce11..41708222 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt @@ -59,7 +59,7 @@ class SearchStore( private fun actionInit(action: Action.Init) { updateState { currentState -> - currentState.copy(query = action.args.checkedQuery) + currentState.copy(query = action.screen.query.trimEnd()) } searchHistory.launch { data -> updateState { currentState -> @@ -110,7 +110,7 @@ class SearchStore( runCatching { interactor.clearHistory() }.onFailure { error -> - Logger.exception(error) + Logger.e(error) } } } diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStoreComponent.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStoreComponent.kt index 5d66d8d8..970ac88e 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStoreComponent.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStoreComponent.kt @@ -2,7 +2,7 @@ package st.slex.csplashscreen.feature.search.ui.presenter import androidx.compose.runtime.Stable import androidx.paging.PagingData -import st.slex.csplashscreen.core.navigation.AppArguments +import st.slex.csplashscreen.core.navigation.Screen import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.core.ui.mvi.StoreComponent import st.slex.csplashscreen.feature.search.ui.model.SearchItem @@ -45,31 +45,21 @@ interface SearchStoreComponent { sealed interface Action : StoreComponent.Action { @Stable - data class Init( - val args: AppArguments.SearchPhotosScreen - ) : Action + data class Init(val screen: Screen.SearchPhotosScreen) : Action @Stable data object ClearHistory : Action @Stable - data class OnImageClick( - val uuid: String - ) : Action + data class OnImageClick(val uuid: String) : Action @Stable - data class OnProfileClick( - val username: String - ) : Action + data class OnProfileClick(val username: String) : Action @Stable - data class OnQueryInput( - val query: String - ) : Action + data class OnQueryInput(val query: String) : Action @Stable - data class OnSearchHistoryClick( - val query: String - ) : Action + data class OnSearchHistoryClick(val query: String) : Action } } diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt index 9c0f1caf..675cffcd 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt @@ -8,9 +8,8 @@ import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState -import st.slex.csplashscreen.core.navigation.AppArguments -import st.slex.csplashscreen.core.navigation.AppDestination -import st.slex.csplashscreen.core.ui.base.createScreen +import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.ui.base.screen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent import st.slex.csplashscreen.feature.user.ui.UserScreen import st.slex.csplashscreen.feature.user.ui.presenter.UserStore @@ -25,10 +24,7 @@ import st.slex.csplashscreen.feature.user.ui.state.rememberUserSwipeState fun NavGraphBuilder.userGraph( modifier: Modifier = Modifier, ) { - createScreen(AppDestination.USER) { store: UserStore, args -> - val arguments = args.firstOrNull() - .orEmpty() - .let(AppArguments::UserScreen) + screen { screen, store -> val state by remember { store.state }.collectAsState() @@ -36,16 +32,16 @@ fun NavGraphBuilder.userGraph( store.state.mapState { it.photos } }.collectAsLazyPagingItems() - val likes = remember(arguments) { + val likes = remember(screen) { store.state.mapState { it.likes } }.collectAsLazyPagingItems() - val collections = remember(arguments) { + val collections = remember(screen) { store.state.mapState { it.collections } }.collectAsLazyPagingItems() - LaunchedEffect(arguments) { - store.sendAction(Init(arguments)) + LaunchedEffect(screen) { + store.sendAction(Init(screen)) } store.event.CollectAsEvent { event -> diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouterImpl.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouterImpl.kt index 5e2901b7..69c3745f 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouterImpl.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouterImpl.kt @@ -1,5 +1,8 @@ package st.slex.csplashscreen.feature.user.navigation +import st.slex.csplashscreen.core.navigation.Screen.CollectionScreen +import st.slex.csplashscreen.core.navigation.Screen.ImageDetailScreen +import st.slex.csplashscreen.core.navigation.Screen.UserScreen import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.PopBackStack import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator @@ -19,18 +22,18 @@ class UserRouterImpl( } private fun popBack() { - navigator.navigate(PopBackStack) + navigator(PopBackStack) } private fun navToUser(event: Navigation.User) { - navigator.navigate(Screen.UserScreen(event.username)) + navigator(Screen(UserScreen(event.username))) } private fun navToImage(event: Navigation.Image) { - navigator.navigate(Screen.ImageDetailScreen(event.uuid)) + navigator(Screen(ImageDetailScreen(event.uuid))) } private fun navToCollection(event: Navigation.Collection) { - navigator.navigate(Screen.CollectionScreen(event.uuid)) + navigator(Screen(CollectionScreen(event.uuid))) } } \ No newline at end of file diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt index d730bdf9..5fd8513d 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt @@ -42,28 +42,28 @@ class UserStore( action: Action.Init ) { interactor - .getUser(action.args.username) + .getUser(action.screen.username) .launch { user -> updateState { currentState -> currentState.copy(user = user) } } - getPhotos(action.args.username) + getPhotos(action.screen.username) .launch { photos -> updateState { currentState -> currentState.copy(photos = photos) } } - getLikes(action.args.username) + getLikes(action.screen.username) .launch { likes -> updateState { currentState -> currentState.copy(likes = likes) } } - getCollections(action.args.username) + getCollections(action.screen.username) .launch { collections -> updateState { currentState -> currentState.copy(collections = collections) diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStoreComponent.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStoreComponent.kt index ec6f701a..bcefa258 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStoreComponent.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStoreComponent.kt @@ -3,7 +3,7 @@ package st.slex.csplashscreen.feature.user.ui.presenter import androidx.compose.runtime.Stable import androidx.paging.PagingData import st.slex.csplashscreen.core.collection.ui.model.CollectionModel -import st.slex.csplashscreen.core.navigation.AppArguments +import st.slex.csplashscreen.core.navigation.Screen import st.slex.csplashscreen.core.network.model.ui.user.UserModel import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.core.ui.mvi.StoreComponent @@ -50,9 +50,7 @@ interface UserStoreComponent { @Stable sealed interface Action : StoreComponent.Action { - data class Init( - val args: AppArguments.UserScreen - ) : Action + data class Init(val screen: Screen.UserScreen) : Action data object OnBackButtonClick : Action diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1a1ed1c8..b25c4250 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] androidDesugarJdkLibs = "2.0.4" kotlin = "2.0.10" -androidGradlePlugin = "8.5.1" -androidTools = "31.5.1" +androidGradlePlugin = "8.5.2" +androidTools = "31.5.2" minSdk = "28" -targetSdk = "34" -compileSdk = "34" +targetSdk = "35" +compileSdk = "35" versionName = "1.73" versionCode = "20" @@ -19,7 +19,7 @@ coroutines = "1.8.1" composeBom = "2024.06.00" composeGradle = "1.6.11" -composeNavigation = "2.7.7" +composeNavigation = "2.8.0-beta07" accompanist = "0.30.0" coilCompose = "2.5.0" composeActivity = "1.9.1" @@ -41,7 +41,7 @@ room = "2.6.1" ksp = "2.0.10-1.0.24" mockito = "2.19.0" vkompose = "0.5.5-k2" -serialization = "1.6.3" +serialization = "1.7.1" paging = "3.3.2" slf4j = "1.7.9" coroutineTest = "1.8.1" From 3080cf00a2c540aee05adc8f11bfddb0a3f9f650 Mon Sep 17 00:00:00 2001 From: stslex Date: Tue, 20 Aug 2024 08:55:38 +0300 Subject: [PATCH 3/3] fix app bar navigation --- .../st/slex/csplashscreen/ui/InitialApp.kt | 9 +++---- .../bottom_appbar/BottomAppBarNavigation.kt | 2 +- .../bottom_appbar/BottomAppBarResource.kt | 26 +++++++++++++------ .../csplashscreen/core/navigation/Screen.kt | 8 ------ 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt b/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt index f49f4d67..e185c2e5 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/InitialApp.kt @@ -27,6 +27,7 @@ import st.slex.csplashscreen.core.navigation.Screen import st.slex.csplashscreen.ui.components.NavHostControllerHolder import st.slex.csplashscreen.ui.components.NavigationHost import st.slex.csplashscreen.ui.components.bottom_appbar.BottomAppBarResource +import st.slex.csplashscreen.ui.components.bottom_appbar.BottomAppBarResource.Companion.getByRoute import st.slex.csplashscreen.ui.components.bottom_appbar.MainBottomAppBar @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @@ -45,11 +46,9 @@ fun InitialApp( } navControllerHolder.navController.addOnDestinationChangedListener { _, destination, _ -> - Logger.d("Destination: ${destination.route}") - // todo need reflection to get Screen by route - currentDestination = destination.route?.let { - Screen.getByRoute(it) - } + Logger.d("current route: ${destination.route}") + currentDestination = destination.route?.let(::getByRoute) + Logger.d("currentDestination: ${currentDestination}") } DisposableEffect(systemUiController, isDarkTheme) { diff --git a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt index c6892293..9b24d8ab 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarNavigation.kt @@ -26,7 +26,7 @@ fun MainBottomAppBar( BottomAppBarResource .entries .forEach { item -> - val isSelected = currentDestination == item.appDestination + val isSelected = currentDestination == item.screen BottomAppBarItem( item = item, isSelected = isSelected, diff --git a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt index 93393099..679b659a 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/components/bottom_appbar/BottomAppBarResource.kt @@ -10,40 +10,50 @@ import androidx.compose.material.icons.outlined.Search import androidx.compose.ui.graphics.vector.ImageVector import st.slex.csplashscreen.R import st.slex.csplashscreen.core.navigation.Screen +import st.slex.csplashscreen.core.navigation.Screen.Favourite +import st.slex.csplashscreen.core.navigation.Screen.Home +import st.slex.csplashscreen.core.navigation.Screen.SearchPhotosScreen +import kotlin.reflect.KClass enum class BottomAppBarResource( val unselectedIcon: ImageVector, val selectedIcon: ImageVector, - val appDestination: Screen, val titleResource: Int, val screen: Screen ) { FAVOURITE( unselectedIcon = Icons.Outlined.FavoriteBorder, selectedIcon = Icons.Filled.Favorite, - appDestination = Screen.Favourite, titleResource = R.string.nav_title_favourite, - screen = Screen.Favourite + screen = Favourite ), HOME( unselectedIcon = Icons.Outlined.Home, selectedIcon = Icons.Filled.Home, - appDestination = Screen.Home, titleResource = R.string.nav_title_home, - screen = Screen.Home + screen = Home ), SEARCH( unselectedIcon = Icons.Outlined.Search, selectedIcon = Icons.Filled.Search, - appDestination = Screen.SearchPhotosScreen(" "), titleResource = R.string.nav_title_search, - screen = Screen.SearchPhotosScreen(query = " ") + screen = SearchPhotosScreen(query = " ") ); fun getIcon(isSelected: Boolean) = if (isSelected) selectedIcon else unselectedIcon companion object { - fun isAppbar(screen: Any?): Boolean = entries.any { it.appDestination == screen } + fun isAppbar(screen: Any?): Boolean = entries.any { it.screen == screen } + + fun getByRoute(route: String): Screen? = when { + Home::class.checkScreen(route) -> HOME + SearchPhotosScreen::class.checkScreen(route) -> SEARCH + Favourite::class.checkScreen(route) -> FAVOURITE + else -> null + }?.screen + + private fun KClass.checkScreen(route: String): Boolean = + route.contains(simpleName.orEmpty()) } } \ No newline at end of file diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt index b477239a..b1f45593 100644 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt +++ b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/Screen.kt @@ -29,14 +29,6 @@ sealed interface Screen { @Serializable data object Favourite : Screen - - companion object { - fun getByRoute(route: String): Screen? = this::class.sealedSubclasses - .firstOrNull { screenClass -> - screenClass.simpleName.orEmpty() - .contains(route, ignoreCase = true) - }?.objectInstance as Screen? - } } inline fun NavGraphBuilder.navScreen(