From 39bd2fab779c40a053634559794c6a1021a71bd5 Mon Sep 17 00:00:00 2001 From: stslex Date: Sun, 19 May 2024 16:51:42 +0300 Subject: [PATCH 1/2] ksp init --- .../main/kotlin/st.slex.csplashscreen/ComposeAndroid.kt | 3 +++ .../main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt | 9 +++++++++ gradle/libs.versions.toml | 9 +++++++++ 3 files changed, 21 insertions(+) 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 2718cf5e..f4a89a26 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 @@ -49,6 +49,9 @@ internal fun Project.configureAndroidCompose( val lifecycle = libs.findBundle("lifecycle").get() add("implementation", lifecycle) + + val koinCompose = libs.findLibrary("koin-compose").get() + add("implementation", koinCompose) } } diff --git a/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt b/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt index fbd8812f..be337f8f 100644 --- a/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt +++ b/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt @@ -73,6 +73,15 @@ internal fun Project.configureKotlinAndroid( val coroutines = libs.findLibrary("coroutines").get() add("implementation", coroutines) + + val koinAndroid = libs.findLibrary("koin-android").get() + add("implementation", koinAndroid) + + val koinAnnotations = libs.findLibrary("koin-annotations").get() + add("implementation", koinAnnotations) + + val koinKsp = libs.findLibrary("koin-ksp").get() + add("ksp", koinKsp) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 950f0972..bb7fe472 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,6 +23,10 @@ accompanist = "0.30.0" coilCompose = "2.5.0" composeActivity = "1.9.0" +koinAndroid = "3.5.6" +koinCompose = "1.1.5" +koinKsp = "1.3.1" + ktor = "2.3.6" ktorAndroid = "2.2.4" okhttp3 = "4.12.0" @@ -107,6 +111,11 @@ androidx-room-testing = { group = "androidx.room", name = "room-testing", versio dagger-core = { group = "com.google.dagger", name = "dagger", version.ref = "dagger" } dagger-compiler = { group = "com.google.dagger", name = "dagger-compiler", version.ref = "dagger" } +koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koinAndroid" } +koin-compose = { group = "io.insert-koin", name = "koin-compose", version.ref = "koinCompose" } +koin-annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koinKsp" } +koin-ksp = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koinKsp" } + [plugins] kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } From b0988cc51cd8b6346fd2bd5df2afe854a3f98044 Mon Sep 17 00:00:00 2001 From: stslex Date: Mon, 20 May 2024 22:05:23 +0300 Subject: [PATCH 2/2] koin integration --- app/build.gradle.kts | 3 +- .../slex/csplashscreen/SplashApplication.kt | 33 +-- .../st/slex/csplashscreen/di/AppComponent.kt | 37 ++++ .../slex/csplashscreen/di/app/AppComponent.kt | 24 --- .../st/slex/csplashscreen/di/app/AppModule.kt | 15 -- .../csplashscreen/di/main/MainComponent.kt | 38 ---- .../di/main/MainComponentBuilder.kt | 54 ----- .../csplashscreen/di/main/MainDependencies.kt | 14 -- .../slex/csplashscreen/di/main/MainModule.kt | 22 -- .../csplashscreen/ui/InitialAppViewModel.kt | 3 +- .../st/slex/csplashscreen/ui/MainActivity.kt | 35 ++-- app/src/test/kotlin/di/AppModuleTest.kt | 87 ++++++++ .../st.slex.csplashscreen/ComposeAndroid.kt | 2 +- .../st.slex.csplashscreen/KotlinAndroid.kt | 13 +- .../data/CollectionsRepositoryImpl.kt | 3 +- .../core/collection/di/CollectionApi.kt | 8 - .../collection/di/CollectionApiBuilder.kt | 19 -- .../core/collection/di/CollectionComponent.kt | 31 --- .../collection/di/CollectionDependencies.kt | 8 - .../core/collection/di/CollectionModule.kt | 13 -- .../collection/di/ModuleCoreCollection.kt | 11 + .../csplashscreen/core/core/api/AppApi.kt | 11 - .../core/core/api/ApplicationApiProvider.kt | 6 - .../core/core/coroutine/AppDispatcherImpl.kt | 3 +- .../csplashscreen/core/core/di/moduleCore.kt | 11 + .../core/database/di/DatabaseApi.kt | 11 - .../core/database/di/DatabaseApiBuilder.kt | 14 -- .../core/database/di/DatabaseComponent.kt | 18 -- .../core/database/di/DatabaseDependencies.kt | 8 - .../di/DatabaseDependenciesComponent.kt | 15 -- .../core/database/di/DatabaseModule.kt | 31 --- .../core/database/di/ModuleCoreDatabase.kt | 22 ++ .../repository/FavouriteRepositoryImpl.kt | 5 +- .../core/favourite/di/FavouriteApi.kt | 11 - .../core/favourite/di/FavouriteApiBuilder.kt | 19 -- .../core/favourite/di/FavouriteComponent.kt | 18 -- .../favourite/di/FavouriteDependencies.kt | 8 - .../di/FavouriteDependenciesComponent.kt | 14 -- ...ouriteModule.kt => ModuleCoreFavourite.kt} | 19 +- .../domain/FavouriteInteractorImpl.kt | 3 +- .../core/navigation/di/NavigationApi.kt | 8 - .../core/navigation/di/NavigationComponent.kt | 21 -- .../di/NavigationComponentBuilder.kt | 18 -- .../core/navigation/di/NavigationModule.kt | 15 +- .../navigation/navigator/NavigatorImpl.kt | 3 +- .../core/network/client/NetworkClientImpl.kt | 5 +- ...rkClientModule.kt => ModuleCoreNetwork.kt} | 49 ++--- .../core/network/di/NetworkApiBuilder.kt | 16 -- .../core/network/di/NetworkClientApi.kt | 20 -- .../core/network/di/NetworkClientComponent.kt | 19 -- .../core/network/di/NetworkDependencies.kt | 8 - .../di/NetworkDependenciesComponent.kt | 16 -- .../impl/CollectionNetworkClientImpl.kt | 5 +- .../source/impl/PhotosNetworkClientImpl.kt | 7 +- .../impl/SearchPhotosNetworkSourceImpl.kt | 5 +- .../source/impl/TopicsNetworkSourceImpl.kt | 5 +- .../source/impl/UserNetworkSourceImpl.kt | 5 +- .../core/photos/data/PhotosRepositoryImpl.kt | 5 +- .../core/photos/di/CorePhotosComponent.kt | 29 --- .../core/photos/di/ModuleCorePhotos.kt | 14 +- .../csplashscreen/core/photos/di/PhotosApi.kt | 8 - .../core/photos/di/PhotosApiBuilder.kt | 19 -- .../core/photos/di/PhotosDependencies.kt | 8 - .../core/ui/base/DaggerViewModel.kt | 55 +---- .../core/ui/base/ViewModelFactory.kt | 25 --- .../csplashscreen/core/ui/di/MainUiApi.kt | 6 - .../core/ui/di/MainUiProvider.kt | 6 - .../csplashscreen/core/ui/di/ViewModelKey.kt | 14 -- .../core/ui/di/builder/Feature.kt | 12 -- .../core/ui/di/builder/FeatureBuilder.kt | 55 ----- .../core/ui/di/builder/FeatureCollector.kt | 16 -- .../core/ui/mvi/BaseViewModel.kt | 109 ---------- .../slex/csplashscreen/core/ui/mvi/Router.kt | 2 +- .../slex/csplashscreen/core/ui/mvi/Store.kt | 109 +++++++++- .../core/ui/mvi/StoreComponent.kt | 12 ++ .../data/SingleCollectionRepositoryImpl.kt | 3 +- .../di/ModuleFeatureSingleCollection.kt | 20 ++ .../collection/di/SingleCollectionBuilder.kt | 24 --- .../di/SingleCollectionComponent.kt | 40 ---- .../di/SingleCollectionDependencies.kt | 14 -- .../collection/di/SingleCollectionModule.kt | 41 ---- .../collection/di/SingleCollectionScope.kt | 7 - .../domain/SingleCollectionInteractorImpl.kt | 3 +- .../navigation/SingleCollectionGraph.kt | 20 +- .../navigation/SingleCollectionRouter.kt | 2 +- .../navigation/SingleCollectionRouterImpl.kt | 5 +- .../ui/presenter/SingleCollectionStore.kt | 118 +++++++---- .../SingleCollectionStoreComponent.kt | 58 ++++++ .../ui/presenter/SingleCollectionViewModel.kt | 95 --------- .../favourite/src/main/AndroidManifest.xml | 4 +- .../favourite/di/FavouriteComponent.kt | 39 ---- .../favourite/di/FavouriteComponentBuilder.kt | 22 -- .../favourite/di/FavouriteDependencies.kt | 14 -- .../feature/favourite/di/FavouriteModule.kt | 35 ---- .../feature/favourite/di/FavouriteScope.kt | 7 - .../favourite/di/ModuleFeatureFavourite.kt | 17 ++ .../domain/FavouriteInteractorImpl.kt | 3 +- .../favourite/navigation/FavouriteGraph.kt | 20 +- .../favourite/navigation/FavouriteRouter.kt | 2 +- .../navigation/FavouriteRouterImpl.kt | 5 +- .../favourite/ui/presenter/FavouriteStore.kt | 92 ++++----- .../ui/presenter/FavouriteStoreComponent.kt | 58 ++++++ .../ui/presenter/FavouriteViewModel.kt | 57 ----- .../feature/home/di/HomeComponent.kt | 41 ---- .../feature/home/di/HomeComponentBuilder.kt | 25 --- .../feature/home/di/HomeDependencies.kt | 17 -- .../feature/home/di/HomeModule.kt | 35 ---- .../feature/home/di/HomeScope.kt | 7 - .../feature/home/di/ModuleFeatureHome.kt | 17 ++ .../feature/home/domain/HomeInteractorImpl.kt | 3 +- .../feature/home/navigation/HomeGraph.kt | 24 +-- .../feature/home/navigation/HomeRouter.kt | 4 +- .../feature/home/navigation/HomeRouterImpl.kt | 5 +- .../feature/home/ui/presenter/HomeStore.kt | 110 +++++----- .../home/ui/presenter/HomeStoreComponent.kt | 68 ++++++ .../home/ui/presenter/HomeViewModel.kt | 81 -------- .../di/ImageDetailComponent.kt | 40 ---- .../di/ImageDetailComponentBuilder.kt | 23 --- .../di/ImageDetailDependencies.kt | 23 --- .../di/ImageDetailModule.kt | 47 ----- .../di/ImageDetailScope.kt | 7 - .../di/ModuleFeatureImageDetail.kt | 23 +++ .../interactor/ImageDetailInteractorImpl.kt | 3 +- .../navigation/ImageDetailGraph.kt | 34 ++- .../navigation/ImageDetailRouter.kt | 2 +- .../navigation/ImageDetailRouterImpl.kt | 5 +- .../ui/ImageDetailScreen.kt | 2 +- .../components/dialogs/DownloadImageDialog.kt | 6 +- .../ui/presenter/ImageDetailStore.kt | 194 +++++++++--------- .../ui/presenter/ImageDetailStoreComponent.kt | 111 ++++++++++ .../ui/presenter/ImageDetailViewModel.kt | 122 ----------- .../ui/utils/DownloadImageUseCaseImpl.kt | 3 +- .../ui/utils/WallpaperSetUseCaseImpl.kt | 3 +- .../search/data/SearchRepositoryImpl.kt | 3 +- .../search/di/ModuleFeatureSearchPhotos.kt | 21 ++ .../search/di/SearchPhotosComponent.kt | 17 -- .../search/di/SearchPhotosComponentBuilder.kt | 25 --- .../search/di/SearchPhotosDependencies.kt | 17 -- .../di/SearchPhotosDependenciesComponent.kt | 26 --- .../feature/search/di/SearchPhotosModule.kt | 42 ---- .../feature/search/di/SearchPhotosScope.kt | 7 - .../interactor/SearchPhotosInteractorImpl.kt | 3 +- .../search/navigation/SearchPhotosGraph.kt | 30 ++- .../search/navigation/SearchPhotosRouter.kt | 2 +- .../navigation/SearchPhotosRouterImpl.kt | 5 +- .../search/ui/presenter/SearchStore.kt | 159 +++++++++----- .../ui/presenter/SearchStoreComponent.kt | 75 +++++++ .../search/ui/presenter/SearchViewModel.kt | 126 ------------ .../feature/user/data/UserRepositoryImpl.kt | 3 +- .../feature/user/di/ModuleFeatureUser.kt | 20 ++ .../feature/user/di/UserComponent.kt | 42 ---- .../feature/user/di/UserComponentBuilder.kt | 25 --- .../feature/user/di/UserDependencies.kt | 20 -- .../feature/user/di/UserModule.kt | 41 ---- .../feature/user/di/UserScope.kt | 7 - .../feature/user/domain/UserInteractorImpl.kt | 3 +- .../feature/user/navigation/UserGraph.kt | 38 ++-- .../feature/user/navigation/UserRouter.kt | 4 +- .../feature/user/navigation/UserRouterImpl.kt | 5 +- .../feature/user/ui/UserScreen.kt | 4 +- .../feature/user/ui/presenter/UserStore.kt | 169 ++++++++++----- .../user/ui/presenter/UserStoreComponent.kt | 72 +++++++ .../user/ui/presenter/UserViewModel.kt | 134 ------------ gradle/libs.versions.toml | 30 ++- 164 files changed, 1565 insertions(+), 2969 deletions(-) create mode 100644 app/src/main/java/st/slex/csplashscreen/di/AppComponent.kt delete mode 100644 app/src/main/java/st/slex/csplashscreen/di/app/AppComponent.kt delete mode 100644 app/src/main/java/st/slex/csplashscreen/di/app/AppModule.kt delete mode 100644 app/src/main/java/st/slex/csplashscreen/di/main/MainComponent.kt delete mode 100644 app/src/main/java/st/slex/csplashscreen/di/main/MainComponentBuilder.kt delete mode 100644 app/src/main/java/st/slex/csplashscreen/di/main/MainDependencies.kt delete mode 100644 app/src/main/java/st/slex/csplashscreen/di/main/MainModule.kt create mode 100644 app/src/test/kotlin/di/AppModuleTest.kt delete mode 100644 core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApi.kt delete mode 100644 core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApiBuilder.kt delete mode 100644 core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionComponent.kt delete mode 100644 core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionDependencies.kt delete mode 100644 core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionModule.kt create mode 100644 core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/ModuleCoreCollection.kt delete mode 100644 core/core/src/main/java/st/slex/csplashscreen/core/core/api/AppApi.kt delete mode 100644 core/core/src/main/java/st/slex/csplashscreen/core/core/api/ApplicationApiProvider.kt create mode 100644 core/core/src/main/java/st/slex/csplashscreen/core/core/di/moduleCore.kt delete mode 100644 core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApi.kt delete mode 100644 core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApiBuilder.kt delete mode 100644 core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseComponent.kt delete mode 100644 core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependencies.kt delete mode 100644 core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependenciesComponent.kt delete mode 100644 core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseModule.kt create mode 100644 core/database/src/main/java/st/slex/csplashscreen/core/database/di/ModuleCoreDatabase.kt delete mode 100644 core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApi.kt delete mode 100644 core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApiBuilder.kt delete mode 100644 core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteComponent.kt delete mode 100644 core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependencies.kt delete mode 100644 core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependenciesComponent.kt rename core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/{FavouriteModule.kt => ModuleCoreFavourite.kt} (52%) delete mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationApi.kt delete mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponent.kt delete mode 100644 core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponentBuilder.kt rename core/network/src/main/java/st/slex/csplashscreen/core/network/di/{NetworkClientModule.kt => ModuleCoreNetwork.kt} (54%) delete mode 100644 core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkApiBuilder.kt delete mode 100644 core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientApi.kt delete mode 100644 core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientComponent.kt delete mode 100644 core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependencies.kt delete mode 100644 core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependenciesComponent.kt delete mode 100644 core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/CorePhotosComponent.kt delete mode 100644 core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApi.kt delete mode 100644 core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApiBuilder.kt delete mode 100644 core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosDependencies.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/ViewModelFactory.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiApi.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiProvider.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/ViewModelKey.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/Feature.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureBuilder.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureCollector.kt delete mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt create mode 100644 core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/StoreComponent.kt create mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/ModuleFeatureSingleCollection.kt delete mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionBuilder.kt delete mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionComponent.kt delete mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionDependencies.kt delete mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionModule.kt delete mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionScope.kt create mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStoreComponent.kt delete mode 100644 feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt delete mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponent.kt delete mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponentBuilder.kt delete mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteDependencies.kt delete mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteModule.kt delete mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteScope.kt create mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/ModuleFeatureFavourite.kt create mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStoreComponent.kt delete mode 100644 feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt delete mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponent.kt delete mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponentBuilder.kt delete mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeDependencies.kt delete mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeModule.kt delete mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeScope.kt create mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/ModuleFeatureHome.kt create mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStoreComponent.kt delete mode 100644 feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt delete mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponent.kt delete mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponentBuilder.kt delete mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailDependencies.kt delete mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailModule.kt delete mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailScope.kt create mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ModuleFeatureImageDetail.kt create mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStoreComponent.kt delete mode 100644 feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt create mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/ModuleFeatureSearchPhotos.kt delete mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponent.kt delete mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponentBuilder.kt delete mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependencies.kt delete mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependenciesComponent.kt delete mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosModule.kt delete mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosScope.kt create mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStoreComponent.kt delete mode 100644 feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt create mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/ModuleFeatureUser.kt delete mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponent.kt delete mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponentBuilder.kt delete mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserDependencies.kt delete mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserModule.kt delete mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserScope.kt create mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStoreComponent.kt delete mode 100644 feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e4842c99..7168cb66 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,7 +6,8 @@ plugins { dependencies { implementation(project(":core:core")) implementation(project(":core:ui")) - + implementation(project(":core:database")) + implementation(project(":core:collection")) implementation(project(":core:navigation")) implementation(project(":core:network")) diff --git a/app/src/main/java/st/slex/csplashscreen/SplashApplication.kt b/app/src/main/java/st/slex/csplashscreen/SplashApplication.kt index cff552b5..9ae0b92d 100644 --- a/app/src/main/java/st/slex/csplashscreen/SplashApplication.kt +++ b/app/src/main/java/st/slex/csplashscreen/SplashApplication.kt @@ -1,25 +1,26 @@ package st.slex.csplashscreen import android.app.Application -import st.slex.csplashscreen.core.core.api.AppApi -import st.slex.csplashscreen.core.core.api.ApplicationApiProvider -import st.slex.csplashscreen.di.app.AppComponent -import st.slex.csplashscreen.di.app.DaggerAppComponent +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.GlobalContext.startKoin +import org.koin.core.logger.Level +import st.slex.csplashscreen.di.AppModules -class SplashApplication : Application(), ApplicationApiProvider { - - private val appComponent: AppComponent by lazy { - DaggerAppComponent - .builder() - .context(this) - .build() - } - - override val appApi: AppApi - get() = appComponent +class SplashApplication : Application() { override fun onCreate() { - appComponent.inject(this) super.onCreate() + initKoin() + } + + private fun initKoin() { + startKoin { + androidLogger( + level = if (BuildConfig.DEBUG) Level.ERROR else Level.NONE + ) + androidContext(this@SplashApplication) + modules(AppModules) + } } } \ No newline at end of file diff --git a/app/src/main/java/st/slex/csplashscreen/di/AppComponent.kt b/app/src/main/java/st/slex/csplashscreen/di/AppComponent.kt new file mode 100644 index 00000000..9be63e00 --- /dev/null +++ b/app/src/main/java/st/slex/csplashscreen/di/AppComponent.kt @@ -0,0 +1,37 @@ +package st.slex.csplashscreen.di + +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.dsl.module +import st.slex.csplashscreen.core.collection.di.moduleCoreCollection +import st.slex.csplashscreen.core.core.di.moduleCore +import st.slex.csplashscreen.core.database.di.moduleCoreDatabase +import st.slex.csplashscreen.core.favourite.di.moduleCoreFavourite +import st.slex.csplashscreen.core.network.di.moduleCoreNetwork +import st.slex.csplashscreen.core.photos.di.moduleCorePhotos +import st.slex.csplashscreen.feature.collection.di.moduleFeatureSingleCollection +import st.slex.csplashscreen.feature.favourite.di.moduleFeatureFavourite +import st.slex.csplashscreen.feature.feature_photo_detail.di.moduleFeatureImageDetail +import st.slex.csplashscreen.feature.home.di.moduleFeatureHome +import st.slex.csplashscreen.feature.search.di.moduleFeatureSearchPhotos +import st.slex.csplashscreen.feature.user.di.moduleFeatureUser +import st.slex.csplashscreen.ui.InitialAppViewModel + +internal val appModule = module { + viewModelOf(::InitialAppViewModel) +} + +val AppModules = listOf( + appModule, + moduleCore, + moduleCoreCollection, + moduleCoreDatabase, + moduleCoreFavourite, + moduleCoreNetwork, + moduleCorePhotos, + moduleFeatureSingleCollection, + moduleFeatureFavourite, + moduleFeatureHome, + moduleFeatureImageDetail, + moduleFeatureSearchPhotos, + moduleFeatureUser +) diff --git a/app/src/main/java/st/slex/csplashscreen/di/app/AppComponent.kt b/app/src/main/java/st/slex/csplashscreen/di/app/AppComponent.kt deleted file mode 100644 index ac437eb6..00000000 --- a/app/src/main/java/st/slex/csplashscreen/di/app/AppComponent.kt +++ /dev/null @@ -1,24 +0,0 @@ -package st.slex.csplashscreen.di.app - -import android.content.Context -import dagger.BindsInstance -import dagger.Component -import st.slex.csplashscreen.SplashApplication -import st.slex.csplashscreen.core.core.api.AppApi -import javax.inject.Singleton - -@Singleton -@Component(modules = [AppModule::class]) -interface AppComponent : AppApi { - - @Component.Builder - interface Builder { - - @BindsInstance - fun context(context: Context): Builder - - fun build(): AppComponent - } - - fun inject(application: SplashApplication) -} diff --git a/app/src/main/java/st/slex/csplashscreen/di/app/AppModule.kt b/app/src/main/java/st/slex/csplashscreen/di/app/AppModule.kt deleted file mode 100644 index d3dae89a..00000000 --- a/app/src/main/java/st/slex/csplashscreen/di/app/AppModule.kt +++ /dev/null @@ -1,15 +0,0 @@ -package st.slex.csplashscreen.di.app - -import dagger.Binds -import dagger.Module -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.core.coroutine.AppDispatcherImpl -import javax.inject.Singleton - -@Module -interface AppModule { - - @Binds - @Singleton - fun bindsAppDispatcher(impl: AppDispatcherImpl): AppDispatcher -} \ No newline at end of file diff --git a/app/src/main/java/st/slex/csplashscreen/di/main/MainComponent.kt b/app/src/main/java/st/slex/csplashscreen/di/main/MainComponent.kt deleted file mode 100644 index c0844f64..00000000 --- a/app/src/main/java/st/slex/csplashscreen/di/main/MainComponent.kt +++ /dev/null @@ -1,38 +0,0 @@ -package st.slex.csplashscreen.di.main - -import androidx.lifecycle.ViewModelProvider -import dagger.Component -import st.slex.csplashscreen.core.core.api.AppApi -import st.slex.csplashscreen.core.navigation.di.NavigationApi -import st.slex.csplashscreen.core.ui.di.MainUiApi - -@Component( - dependencies = [MainDependencies::class], - modules = [MainModule::class] -) -interface MainComponent : MainUiApi { - - @Component.Factory - interface Factory { - fun create(dependencies: MainDependencies): MainComponent - } - - @Component( - dependencies = [ - NavigationApi::class, - AppApi::class - ] - ) - interface MainDependenciesComponent : MainDependencies { - - @Component.Factory - interface Factory { - fun create( - appApi: AppApi, - navigationApi: NavigationApi - ): MainDependenciesComponent - } - } - - val viewModelFactory: ViewModelProvider.Factory -} diff --git a/app/src/main/java/st/slex/csplashscreen/di/main/MainComponentBuilder.kt b/app/src/main/java/st/slex/csplashscreen/di/main/MainComponentBuilder.kt deleted file mode 100644 index 6ae4d4ba..00000000 --- a/app/src/main/java/st/slex/csplashscreen/di/main/MainComponentBuilder.kt +++ /dev/null @@ -1,54 +0,0 @@ -package st.slex.csplashscreen.di.main - -import android.content.Context -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext -import androidx.navigation.NavHostController -import st.slex.csplashscreen.core.core.api.AppApi -import st.slex.csplashscreen.core.core.api.ApplicationApiProvider -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.navigation.di.NavigationApi -import st.slex.csplashscreen.core.navigation.di.NavigationComponentBuilder - -object MainComponentBuilder { - - private var component: MainComponent? = null - - fun build( - appApi: AppApi, - navigationApi: NavigationApi, - ): MainComponent = component ?: DaggerMainComponent - .factory() - .create( - DaggerMainComponent_MainDependenciesComponent.factory() - .create( - appApi = appApi, - navigationApi = navigationApi - ) - ) - .also { - component = it - } -} - -@Composable -fun buildMainUIApi( - navHostController: NavHostController -): MainComponent { - val navigationApi = remember(navHostController) { - NavigationComponentBuilder - .build(navHostController) - } - val context = LocalContext.current - val appApi = (context.applicationContext as ApplicationApiProvider).appApi - return remember(navHostController) { - MainComponentBuilder.build( - appApi = object : AppApi { - override val context: Context = context - override val appDispatcher: AppDispatcher = appApi.appDispatcher - }, - navigationApi = navigationApi - ) - } -} diff --git a/app/src/main/java/st/slex/csplashscreen/di/main/MainDependencies.kt b/app/src/main/java/st/slex/csplashscreen/di/main/MainDependencies.kt deleted file mode 100644 index 5762d999..00000000 --- a/app/src/main/java/st/slex/csplashscreen/di/main/MainDependencies.kt +++ /dev/null @@ -1,14 +0,0 @@ -package st.slex.csplashscreen.di.main - -import android.content.Context -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.navigation.navigator.Navigator - -interface MainDependencies { - - val navigator: Navigator - - val context: Context - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/app/src/main/java/st/slex/csplashscreen/di/main/MainModule.kt b/app/src/main/java/st/slex/csplashscreen/di/main/MainModule.kt deleted file mode 100644 index 8e121886..00000000 --- a/app/src/main/java/st/slex/csplashscreen/di/main/MainModule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package st.slex.csplashscreen.di.main - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import st.slex.csplashscreen.core.ui.base.ViewModelFactory -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import st.slex.csplashscreen.core.ui.di.ViewModelKey -import st.slex.csplashscreen.ui.InitialAppViewModel - -@Module -interface MainModule { - - @Binds - @IntoMap - @ViewModelKey(InitialAppViewModel::class) - fun bindsViewModel(impl: InitialAppViewModel): ViewModel - - @Binds - fun bindsFactory(impl: ViewModelFactory): ViewModelProvider.Factory -} \ No newline at end of file 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 c4d4056d..97623dc0 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/InitialAppViewModel.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/InitialAppViewModel.kt @@ -3,9 +3,8 @@ package st.slex.csplashscreen.ui import androidx.lifecycle.ViewModel import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget import st.slex.csplashscreen.core.navigation.navigator.Navigator -import javax.inject.Inject -class InitialAppViewModel @Inject constructor( +class InitialAppViewModel( private val navigator: Navigator ) : ViewModel() { 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 f8bcd4f5..7e5ebd0c 100644 --- a/app/src/main/java/st/slex/csplashscreen/ui/MainActivity.kt +++ b/app/src/main/java/st/slex/csplashscreen/ui/MainActivity.kt @@ -6,18 +6,14 @@ import androidx.activity.compose.setContent import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.core.view.WindowCompat +import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController -import st.slex.csplashscreen.core.ui.base.daggerViewModel -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.MainUiProvider +import org.koin.androidx.compose.getKoin +import org.koin.androidx.compose.koinViewModel +import st.slex.csplashscreen.core.navigation.di.moduleCoreNavigation import st.slex.csplashscreen.core.ui.theme.AppTheme -import st.slex.csplashscreen.di.main.buildMainUIApi -class MainActivity : ComponentActivity(), MainUiProvider { - - private var _api: MainUiApi? = null - override val api: MainUiApi - get() = requireNotNull(_api) +class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -25,13 +21,15 @@ class MainActivity : ComponentActivity(), MainUiProvider { WindowCompat.setDecorFitsSystemWindows(window, false) setContent { AppTheme { - val viewModel = buildViewModel() + val navHostController = rememberNavController() + SetupComposeDependencies(navHostController) + val viewModel = koinViewModel() InitialApp( /*TODO AFTER reconfiguration controller in VM don't change it State, so it need to have latest instance. Need Research to find more efficient way */ - navController = api.navigator.controller, + navController = navHostController, onBottomAppBarClick = remember { { viewModel.navigate(it) } } @@ -41,14 +39,13 @@ class MainActivity : ComponentActivity(), MainUiProvider { } @Composable - private fun buildViewModel(): InitialAppViewModel { - val navHostController = rememberNavController() - val component = buildMainUIApi( - navHostController = navHostController + private fun SetupComposeDependencies( + navController: NavHostController + ) { + getKoin().loadModules( + listOf( + moduleCoreNavigation(navController), + ) ) - _api = component - return daggerViewModel { - component.viewModelFactory - } } } diff --git a/app/src/test/kotlin/di/AppModuleTest.kt b/app/src/test/kotlin/di/AppModuleTest.kt new file mode 100644 index 00000000..8bf9b948 --- /dev/null +++ b/app/src/test/kotlin/di/AppModuleTest.kt @@ -0,0 +1,87 @@ +package di + +import android.content.Context +import androidx.navigation.NavHostController +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestWatcher +import org.junit.runner.Description +import org.koin.dsl.koinApplication +import org.koin.test.KoinTest +import org.koin.test.check.checkModules +import org.koin.test.mock.MockProviderRule +import org.mockito.Mockito +import st.slex.csplashscreen.core.collection.di.moduleCoreCollection +import st.slex.csplashscreen.core.core.di.moduleCore +import st.slex.csplashscreen.core.database.di.moduleCoreDatabase +import st.slex.csplashscreen.core.favourite.di.moduleCoreFavourite +import st.slex.csplashscreen.core.navigation.di.moduleCoreNavigation +import st.slex.csplashscreen.core.network.di.moduleCoreNetwork +import st.slex.csplashscreen.core.photos.di.moduleCorePhotos +import st.slex.csplashscreen.di.appModule +import st.slex.csplashscreen.feature.collection.di.moduleFeatureSingleCollection +import st.slex.csplashscreen.feature.favourite.di.moduleFeatureFavourite +import st.slex.csplashscreen.feature.feature_photo_detail.di.moduleFeatureImageDetail +import st.slex.csplashscreen.feature.home.di.moduleFeatureHome +import st.slex.csplashscreen.feature.search.di.moduleFeatureSearchPhotos +import st.slex.csplashscreen.feature.user.di.moduleFeatureUser + +class AppModuleTest : KoinTest { + + @ExperimentalCoroutinesApi + @get:Rule + val mainCoroutineRule = MainCoroutineRule() + + @get:Rule + val mockProvider = MockProviderRule.create { clazz -> + Mockito.mock(clazz.java) + } + + @Test + fun `check koin configuration`() { + val navController = Mockito.mock(NavHostController::class.java) + koinApplication { + modules( + moduleCoreNavigation(navController), + appModule, + moduleCore, + moduleCoreCollection, + moduleCoreDatabase, + moduleCoreFavourite, + moduleCoreNetwork, + moduleCorePhotos, + moduleFeatureSingleCollection, + moduleFeatureFavourite, + moduleFeatureHome, + moduleFeatureImageDetail, + moduleFeatureSearchPhotos, + moduleFeatureUser + ) + checkModules { + withInstance() + } + } + } +} + +@ExperimentalCoroutinesApi +class MainCoroutineRule( + private val dispatcher: TestDispatcher = StandardTestDispatcher() +) : TestWatcher() { + + override fun starting(description: Description?) { + super.starting(description) + Dispatchers.setMain(dispatcher) + } + + override fun finished(description: Description?) { + super.finished(description) + Dispatchers.resetMain() + } +} \ No newline at end of file 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 f4a89a26..38a0815f 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 @@ -50,7 +50,7 @@ internal fun Project.configureAndroidCompose( val lifecycle = libs.findBundle("lifecycle").get() add("implementation", lifecycle) - val koinCompose = libs.findLibrary("koin-compose").get() + val koinCompose = libs.findLibrary("koin-androidx-compose").get() add("implementation", koinCompose) } } diff --git a/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt b/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt index be337f8f..927fbb27 100644 --- a/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt +++ b/build-logic/dependencies/src/main/kotlin/st.slex.csplashscreen/KotlinAndroid.kt @@ -65,20 +65,11 @@ internal fun Project.configureKotlinAndroid( val immutableCollection = libs.findLibrary("kotlinx-collections-immutable").get() add("implementation", immutableCollection) - val dagger = libs.findLibrary("dagger-core").get() - add("implementation", dagger) - - val daggerCompiler = libs.findLibrary("dagger-compiler").get() - add("ksp", daggerCompiler) - val coroutines = libs.findLibrary("coroutines").get() add("implementation", coroutines) - val koinAndroid = libs.findLibrary("koin-android").get() - add("implementation", koinAndroid) - - val koinAnnotations = libs.findLibrary("koin-annotations").get() - add("implementation", koinAnnotations) + val koinBundle = libs.findBundle("koin").get() + add("implementation", koinBundle) val koinKsp = libs.findLibrary("koin-ksp").get() add("ksp", koinKsp) diff --git a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/data/CollectionsRepositoryImpl.kt b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/data/CollectionsRepositoryImpl.kt index 390b5f99..12d913a1 100644 --- a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/data/CollectionsRepositoryImpl.kt +++ b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/data/CollectionsRepositoryImpl.kt @@ -4,9 +4,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import st.slex.csplashscreen.core.network.model.remote.collection.RemoteCollectionModel import st.slex.csplashscreen.core.network.source.interf.CollectionNetworkClient -import javax.inject.Inject -class CollectionsRepositoryImpl @Inject constructor( +class CollectionsRepositoryImpl( private val client: CollectionNetworkClient ) : CollectionsRepository { diff --git a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApi.kt b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApi.kt deleted file mode 100644 index e48c9cf4..00000000 --- a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApi.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.collection.di - -import st.slex.csplashscreen.core.collection.data.CollectionsRepository - -interface CollectionApi { - - val repository: CollectionsRepository -} \ No newline at end of file diff --git a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApiBuilder.kt b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApiBuilder.kt deleted file mode 100644 index 37d1faee..00000000 --- a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionApiBuilder.kt +++ /dev/null @@ -1,19 +0,0 @@ -package st.slex.csplashscreen.core.collection.di - -import st.slex.csplashscreen.core.core.api.AppApi -import st.slex.csplashscreen.core.network.di.NetworkApiBuilder - -object CollectionApiBuilder { - - fun build( - appApi: AppApi - ): CollectionApi = DaggerCollectionComponent - .factory() - .create( - dependencies = DaggerCollectionComponent_CollectionDependenciesComponent - .factory() - .create( - networkClientApi = NetworkApiBuilder.build(appApi) - ) - ) -} \ No newline at end of file diff --git a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionComponent.kt b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionComponent.kt deleted file mode 100644 index e5c01a68..00000000 --- a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionComponent.kt +++ /dev/null @@ -1,31 +0,0 @@ -package st.slex.csplashscreen.core.collection.di - -import dagger.Component -import st.slex.csplashscreen.core.network.di.NetworkClientApi - -@Component( - modules = [CollectionModule::class], - dependencies = [CollectionDependencies::class] -) -interface CollectionComponent : CollectionApi { - - @Component.Factory - interface Factory { - - fun create(dependencies: CollectionDependencies): CollectionApi - } - - @Component( - dependencies = [NetworkClientApi::class] - ) - interface CollectionDependenciesComponent : CollectionDependencies { - - @Component.Factory - interface Factory { - - fun create( - networkClientApi: NetworkClientApi - ): CollectionDependencies - } - } -} \ No newline at end of file diff --git a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionDependencies.kt b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionDependencies.kt deleted file mode 100644 index a5493e26..00000000 --- a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionDependencies.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.collection.di - -import st.slex.csplashscreen.core.network.source.interf.CollectionNetworkClient - -interface CollectionDependencies { - - val client: CollectionNetworkClient -} \ No newline at end of file diff --git a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionModule.kt b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionModule.kt deleted file mode 100644 index f1307aed..00000000 --- a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/CollectionModule.kt +++ /dev/null @@ -1,13 +0,0 @@ -package st.slex.csplashscreen.core.collection.di - -import dagger.Binds -import dagger.Module -import st.slex.csplashscreen.core.collection.data.CollectionsRepository -import st.slex.csplashscreen.core.collection.data.CollectionsRepositoryImpl - -@Module -interface CollectionModule { - - @Binds - fun bindRepository(impl: CollectionsRepositoryImpl): CollectionsRepository -} \ No newline at end of file diff --git a/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/ModuleCoreCollection.kt b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/ModuleCoreCollection.kt new file mode 100644 index 00000000..f79c885c --- /dev/null +++ b/core/collection/src/main/java/st/slex/csplashscreen/core/collection/di/ModuleCoreCollection.kt @@ -0,0 +1,11 @@ +package st.slex.csplashscreen.core.collection.di + +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module +import st.slex.csplashscreen.core.collection.data.CollectionsRepository +import st.slex.csplashscreen.core.collection.data.CollectionsRepositoryImpl + +val moduleCoreCollection = module { + factoryOf(::CollectionsRepositoryImpl) { bind() } +} \ No newline at end of file diff --git a/core/core/src/main/java/st/slex/csplashscreen/core/core/api/AppApi.kt b/core/core/src/main/java/st/slex/csplashscreen/core/core/api/AppApi.kt deleted file mode 100644 index 60824a85..00000000 --- a/core/core/src/main/java/st/slex/csplashscreen/core/core/api/AppApi.kt +++ /dev/null @@ -1,11 +0,0 @@ -package st.slex.csplashscreen.core.core.api - -import android.content.Context -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher - -interface AppApi { - - val context: Context - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/core/core/src/main/java/st/slex/csplashscreen/core/core/api/ApplicationApiProvider.kt b/core/core/src/main/java/st/slex/csplashscreen/core/core/api/ApplicationApiProvider.kt deleted file mode 100644 index cac0a6fe..00000000 --- a/core/core/src/main/java/st/slex/csplashscreen/core/core/api/ApplicationApiProvider.kt +++ /dev/null @@ -1,6 +0,0 @@ -package st.slex.csplashscreen.core.core.api - -interface ApplicationApiProvider { - - val appApi: AppApi -} diff --git a/core/core/src/main/java/st/slex/csplashscreen/core/core/coroutine/AppDispatcherImpl.kt b/core/core/src/main/java/st/slex/csplashscreen/core/core/coroutine/AppDispatcherImpl.kt index d4a211f9..1f0ba120 100644 --- a/core/core/src/main/java/st/slex/csplashscreen/core/core/coroutine/AppDispatcherImpl.kt +++ b/core/core/src/main/java/st/slex/csplashscreen/core/core/coroutine/AppDispatcherImpl.kt @@ -3,9 +3,8 @@ package st.slex.csplashscreen.core.core.coroutine import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.MainCoroutineDispatcher -import javax.inject.Inject -class AppDispatcherImpl @Inject constructor() : AppDispatcher { +class AppDispatcherImpl : AppDispatcher { override val io: CoroutineDispatcher = Dispatchers.IO override val main: MainCoroutineDispatcher = Dispatchers.Main override val default: CoroutineDispatcher = Dispatchers.Default diff --git a/core/core/src/main/java/st/slex/csplashscreen/core/core/di/moduleCore.kt b/core/core/src/main/java/st/slex/csplashscreen/core/core/di/moduleCore.kt new file mode 100644 index 00000000..fdd37d9f --- /dev/null +++ b/core/core/src/main/java/st/slex/csplashscreen/core/core/di/moduleCore.kt @@ -0,0 +1,11 @@ +package st.slex.csplashscreen.core.core.di + +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher +import st.slex.csplashscreen.core.core.coroutine.AppDispatcherImpl + +val moduleCore = module { + singleOf(::AppDispatcherImpl) { bind() } +} \ No newline at end of file diff --git a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApi.kt b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApi.kt deleted file mode 100644 index b936c6ef..00000000 --- a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApi.kt +++ /dev/null @@ -1,11 +0,0 @@ -package st.slex.csplashscreen.core.database.di - -import st.slex.csplashscreen.core.database.favourite.FavouriteDao -import st.slex.csplashscreen.core.database.search.SearchDao - -interface DatabaseApi { - - val searchDao: SearchDao - - val favouriteDao: FavouriteDao -} \ No newline at end of file diff --git a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApiBuilder.kt b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApiBuilder.kt deleted file mode 100644 index 0a80a222..00000000 --- a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseApiBuilder.kt +++ /dev/null @@ -1,14 +0,0 @@ -package st.slex.csplashscreen.core.database.di - -import st.slex.csplashscreen.core.core.api.AppApi - -object DatabaseApiBuilder { - - fun build(appApi: AppApi): DatabaseApi = DaggerDatabaseComponent - .factory() - .create( - dependencies = DaggerDatabaseDependenciesComponent - .factory() - .create(appApi) - ) -} \ No newline at end of file diff --git a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseComponent.kt b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseComponent.kt deleted file mode 100644 index fc71786b..00000000 --- a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseComponent.kt +++ /dev/null @@ -1,18 +0,0 @@ -package st.slex.csplashscreen.core.database.di - -import dagger.Component -import javax.inject.Singleton - -@Component( - dependencies = [DatabaseDependencies::class], - modules = [DatabaseModule::class] -) -@Singleton -interface DatabaseComponent : DatabaseApi { - - @Component.Factory - interface Factory { - fun create(dependencies: DatabaseDependencies): DatabaseApi - } -} - diff --git a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependencies.kt b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependencies.kt deleted file mode 100644 index bd826677..00000000 --- a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependencies.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.database.di - -import android.content.Context - -interface DatabaseDependencies { - - val context: Context -} \ No newline at end of file diff --git a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependenciesComponent.kt b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependenciesComponent.kt deleted file mode 100644 index 0ea10157..00000000 --- a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseDependenciesComponent.kt +++ /dev/null @@ -1,15 +0,0 @@ -package st.slex.csplashscreen.core.database.di - -import dagger.Component -import st.slex.csplashscreen.core.core.api.AppApi -import javax.inject.Singleton - -@Component(dependencies = [AppApi::class]) -@Singleton -interface DatabaseDependenciesComponent : DatabaseDependencies { - - @Component.Factory - interface Factory { - fun create(appApi: AppApi): DatabaseDependencies - } -} \ No newline at end of file diff --git a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseModule.kt b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseModule.kt deleted file mode 100644 index 1537e880..00000000 --- a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/DatabaseModule.kt +++ /dev/null @@ -1,31 +0,0 @@ -package st.slex.csplashscreen.core.database.di - -import android.content.Context -import androidx.room.Room -import dagger.Module -import dagger.Provides -import st.slex.csplashscreen.core.database.AppDatabase -import st.slex.csplashscreen.core.database.favourite.FavouriteDao -import st.slex.csplashscreen.core.database.search.SearchDao -import javax.inject.Singleton - -@Module -class DatabaseModule { - - @Provides - @Singleton - fun provideDatabase(context: Context): AppDatabase = Room.databaseBuilder( - context, - AppDatabase::class.java, - AppDatabase.NAME - ) - .build() - - @Provides - @Singleton - fun provideSearchDao(database: AppDatabase): SearchDao = database.searchDao - - @Provides - @Singleton - fun providesFavouriteDao(database: AppDatabase): FavouriteDao = database.favouriteDao -} \ No newline at end of file diff --git a/core/database/src/main/java/st/slex/csplashscreen/core/database/di/ModuleCoreDatabase.kt b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/ModuleCoreDatabase.kt new file mode 100644 index 00000000..490f25a4 --- /dev/null +++ b/core/database/src/main/java/st/slex/csplashscreen/core/database/di/ModuleCoreDatabase.kt @@ -0,0 +1,22 @@ +package st.slex.csplashscreen.core.database.di + +import androidx.room.Room +import org.koin.android.ext.koin.androidContext +import org.koin.dsl.module +import st.slex.csplashscreen.core.database.AppDatabase +import st.slex.csplashscreen.core.database.favourite.FavouriteDao +import st.slex.csplashscreen.core.database.search.SearchDao + +val moduleCoreDatabase = module { + single { + Room.databaseBuilder( + androidContext(), + AppDatabase::class.java, + AppDatabase.NAME + ) + .build() + } + + single { get().searchDao } + single { get().favouriteDao } +} \ No newline at end of file diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/data/repository/FavouriteRepositoryImpl.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/data/repository/FavouriteRepositoryImpl.kt index 3b1c6a99..20661e78 100644 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/data/repository/FavouriteRepositoryImpl.kt +++ b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/data/repository/FavouriteRepositoryImpl.kt @@ -12,11 +12,8 @@ import st.slex.csplashscreen.core.database.favourite.FavouriteDao import st.slex.csplashscreen.core.favourite.data.model.FavouriteMapper.toDomain import st.slex.csplashscreen.core.favourite.data.model.FavouriteMapper.toEntity import st.slex.csplashscreen.core.photos.ui.model.PhotoModel -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class FavouriteRepositoryImpl @Inject constructor( +class FavouriteRepositoryImpl( private val dao: FavouriteDao ) : FavouriteRepository { diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApi.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApi.kt deleted file mode 100644 index 3407b4fe..00000000 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApi.kt +++ /dev/null @@ -1,11 +0,0 @@ -package st.slex.csplashscreen.core.favourite.di - -import st.slex.csplashscreen.core.favourite.data.repository.FavouriteRepository -import st.slex.csplashscreen.core.favourite.domain.FavouriteInteractor - -interface FavouriteApi { - - val favouriteRepository: FavouriteRepository - - val favouriteInteractor: FavouriteInteractor -} \ No newline at end of file diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApiBuilder.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApiBuilder.kt deleted file mode 100644 index 56705d97..00000000 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteApiBuilder.kt +++ /dev/null @@ -1,19 +0,0 @@ -package st.slex.csplashscreen.core.favourite.di - -import st.slex.csplashscreen.core.core.api.AppApi -import st.slex.csplashscreen.core.database.di.DatabaseApiBuilder - -object FavouriteApiBuilder { - - fun build( - appApi: AppApi - ): FavouriteApi = DaggerFavouriteComponent - .factory() - .create( - dependencies = DaggerFavouriteDependenciesComponent - .factory() - .create( - databaseApi = DatabaseApiBuilder.build(appApi) - ) - ) -} \ No newline at end of file diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteComponent.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteComponent.kt deleted file mode 100644 index b16e536c..00000000 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteComponent.kt +++ /dev/null @@ -1,18 +0,0 @@ -package st.slex.csplashscreen.core.favourite.di - -import dagger.Component -import javax.inject.Singleton - -@Component( - modules = [FavouriteModule::class], - dependencies = [FavouriteDependencies::class] -) -@Singleton -interface FavouriteComponent : FavouriteApi { - - @Component.Factory - interface Factory { - - fun create(dependencies: FavouriteDependencies): FavouriteApi - } -} diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependencies.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependencies.kt deleted file mode 100644 index 5042df80..00000000 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependencies.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.favourite.di - -import st.slex.csplashscreen.core.database.favourite.FavouriteDao - -interface FavouriteDependencies { - - val favouriteDao: FavouriteDao -} \ No newline at end of file diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependenciesComponent.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependenciesComponent.kt deleted file mode 100644 index 4c08faea..00000000 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteDependenciesComponent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package st.slex.csplashscreen.core.favourite.di - -import dagger.Component -import st.slex.csplashscreen.core.database.di.DatabaseApi - -@Component(dependencies = [DatabaseApi::class]) -interface FavouriteDependenciesComponent : FavouriteDependencies { - - @Component.Factory - interface Factory { - - fun create(databaseApi: DatabaseApi): FavouriteDependencies - } -} \ No newline at end of file diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteModule.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/ModuleCoreFavourite.kt similarity index 52% rename from core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteModule.kt rename to core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/ModuleCoreFavourite.kt index 81d47a3e..a58c7bbd 100644 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/FavouriteModule.kt +++ b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/di/ModuleCoreFavourite.kt @@ -1,20 +1,15 @@ package st.slex.csplashscreen.core.favourite.di -import dagger.Binds -import dagger.Module +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module import st.slex.csplashscreen.core.favourite.data.repository.FavouriteRepository import st.slex.csplashscreen.core.favourite.data.repository.FavouriteRepositoryImpl import st.slex.csplashscreen.core.favourite.domain.FavouriteInteractor import st.slex.csplashscreen.core.favourite.domain.FavouriteInteractorImpl -import javax.inject.Singleton -@Module -interface FavouriteModule { - - @Binds - @Singleton - fun bindFavouriteRepository(impl: FavouriteRepositoryImpl): FavouriteRepository - - @Binds - fun bindsFavouriteInteractor(impl: FavouriteInteractorImpl): FavouriteInteractor +val moduleCoreFavourite = module { + singleOf(::FavouriteRepositoryImpl) { bind() } + factoryOf(::FavouriteInteractorImpl) { bind() } } \ No newline at end of file diff --git a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/domain/FavouriteInteractorImpl.kt b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/domain/FavouriteInteractorImpl.kt index a9c64682..960ad498 100644 --- a/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/domain/FavouriteInteractorImpl.kt +++ b/core/favourite/src/main/java/st/slex/csplashscreen/core/favourite/domain/FavouriteInteractorImpl.kt @@ -6,9 +6,8 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import st.slex.csplashscreen.core.favourite.data.repository.FavouriteRepository import st.slex.csplashscreen.core.photos.ui.model.PhotoModel -import javax.inject.Inject -class FavouriteInteractorImpl @Inject constructor( +class FavouriteInteractorImpl( private val repository: FavouriteRepository ) : FavouriteInteractor { diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationApi.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationApi.kt deleted file mode 100644 index 16b7a3dc..00000000 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationApi.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.navigation.di - -import st.slex.csplashscreen.core.navigation.navigator.Navigator - -interface NavigationApi { - - val navigator: Navigator -} \ No newline at end of file diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponent.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponent.kt deleted file mode 100644 index 0537b623..00000000 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponent.kt +++ /dev/null @@ -1,21 +0,0 @@ -package st.slex.csplashscreen.core.navigation.di - -import androidx.navigation.NavHostController -import dagger.BindsInstance -import dagger.Component -import javax.inject.Singleton - -@Component(modules = [NavigationModule::class]) -@Singleton -interface NavigationComponent : NavigationApi { - - @Component.Builder - interface Builder { - - @BindsInstance - fun controller(navHostController: NavHostController): Builder - - fun build(): NavigationApi - } -} - diff --git a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponentBuilder.kt b/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponentBuilder.kt deleted file mode 100644 index 94991c05..00000000 --- a/core/navigation/src/main/java/st/slex/csplashscreen/core/navigation/di/NavigationComponentBuilder.kt +++ /dev/null @@ -1,18 +0,0 @@ -package st.slex.csplashscreen.core.navigation.di - -import androidx.navigation.NavHostController - -object NavigationComponentBuilder { - - private var component: NavigationApi? = null - - fun build( - navHostController: NavHostController - ): NavigationApi = component ?: DaggerNavigationComponent - .builder() - .controller(navHostController) - .build() - .also { - component = it - } -} \ 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 02e48c76..a124a7a4 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 @@ -1,15 +1,12 @@ package st.slex.csplashscreen.core.navigation.di -import dagger.Binds -import dagger.Module +import androidx.navigation.NavHostController +import org.koin.dsl.module import st.slex.csplashscreen.core.navigation.navigator.Navigator import st.slex.csplashscreen.core.navigation.navigator.NavigatorImpl -import javax.inject.Singleton -@Module -interface NavigationModule { - - @Binds - @Singleton - fun bindNavigator(impl: NavigatorImpl): Navigator +fun moduleCoreNavigation(navController: NavHostController) = module { + single { + NavigatorImpl(navController) + } } \ No newline at end of file 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 4bc95d45..34fd8723 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 @@ -2,9 +2,8 @@ package st.slex.csplashscreen.core.navigation.navigator import androidx.navigation.NavHostController import st.slex.csplashscreen.core.core.Logger -import javax.inject.Inject -class NavigatorImpl @Inject constructor( +class NavigatorImpl( private val navController: NavHostController ) : Navigator { diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/client/NetworkClientImpl.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/client/NetworkClientImpl.kt index 21ffe30a..c25df344 100644 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/client/NetworkClientImpl.kt +++ b/core/network/src/main/java/st/slex/csplashscreen/core/network/client/NetworkClientImpl.kt @@ -20,11 +20,8 @@ import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import st.slex.csplashscreen.core.core.coroutine.AppDispatcher import st.slex.csplashscreen.core.network.BuildConfig -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class NetworkClientImpl @Inject constructor( +class NetworkClientImpl( private val appDispatcher: AppDispatcher ) : NetworkClient { diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientModule.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/di/ModuleCoreNetwork.kt similarity index 54% rename from core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientModule.kt rename to core/network/src/main/java/st/slex/csplashscreen/core/network/di/ModuleCoreNetwork.kt index 4502ad84..207d6e9e 100644 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientModule.kt +++ b/core/network/src/main/java/st/slex/csplashscreen/core/network/di/ModuleCoreNetwork.kt @@ -1,45 +1,26 @@ package st.slex.csplashscreen.core.network.di -import dagger.Binds -import dagger.Module +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module import st.slex.csplashscreen.core.network.client.NetworkClient import st.slex.csplashscreen.core.network.client.NetworkClientImpl -import st.slex.csplashscreen.core.network.source.interf.CollectionNetworkClient -import st.slex.csplashscreen.core.network.source.interf.PhotosNetworkClient -import st.slex.csplashscreen.core.network.source.interf.SearchPhotosNetworkSource -import st.slex.csplashscreen.core.network.source.interf.TopicsNetworkSource -import st.slex.csplashscreen.core.network.source.interf.UserNetworkSource import st.slex.csplashscreen.core.network.source.impl.CollectionNetworkClientImpl import st.slex.csplashscreen.core.network.source.impl.PhotosNetworkClientImpl import st.slex.csplashscreen.core.network.source.impl.SearchPhotosNetworkSourceImpl import st.slex.csplashscreen.core.network.source.impl.TopicsNetworkSourceImpl import st.slex.csplashscreen.core.network.source.impl.UserNetworkSourceImpl -import javax.inject.Singleton - -@Module -interface NetworkClientModule { - - @Binds - @Singleton - fun bindsNetworkClient(impl: NetworkClientImpl): NetworkClient - - @Binds - @Singleton - fun bindsCollectionNetworkClient(impl: CollectionNetworkClientImpl): CollectionNetworkClient - - @Binds - @Singleton - fun bindsPhotosNetworkClientImpl(impl: PhotosNetworkClientImpl): PhotosNetworkClient - - @Binds - @Singleton - fun bindsSearchPhotosNetworkSource(impl: SearchPhotosNetworkSourceImpl): SearchPhotosNetworkSource - - @Binds - @Singleton - fun bindsTopicsNetworkSource(impl: TopicsNetworkSourceImpl): TopicsNetworkSource +import st.slex.csplashscreen.core.network.source.interf.CollectionNetworkClient +import st.slex.csplashscreen.core.network.source.interf.PhotosNetworkClient +import st.slex.csplashscreen.core.network.source.interf.SearchPhotosNetworkSource +import st.slex.csplashscreen.core.network.source.interf.TopicsNetworkSource +import st.slex.csplashscreen.core.network.source.interf.UserNetworkSource - @Binds - @Singleton - fun bindsUserNetworkSource(impl: UserNetworkSourceImpl): UserNetworkSource +val moduleCoreNetwork = module { + singleOf(::NetworkClientImpl) { bind() } + singleOf(::CollectionNetworkClientImpl) { bind() } + singleOf(::PhotosNetworkClientImpl) { bind() } + singleOf(::SearchPhotosNetworkSourceImpl) { bind() } + singleOf(::TopicsNetworkSourceImpl) { bind() } + singleOf(::UserNetworkSourceImpl) { bind() } } \ No newline at end of file diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkApiBuilder.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkApiBuilder.kt deleted file mode 100644 index c8eb431b..00000000 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkApiBuilder.kt +++ /dev/null @@ -1,16 +0,0 @@ -package st.slex.csplashscreen.core.network.di - -import st.slex.csplashscreen.core.core.api.AppApi - -object NetworkApiBuilder { - - fun build( - appApi: AppApi - ): NetworkClientApi = DaggerNetworkClientComponent - .factory() - .create( - dependencies = DaggerNetworkDependenciesComponent - .factory() - .create(appApi) - ) -} \ No newline at end of file diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientApi.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientApi.kt deleted file mode 100644 index 49684faf..00000000 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientApi.kt +++ /dev/null @@ -1,20 +0,0 @@ -package st.slex.csplashscreen.core.network.di - -import st.slex.csplashscreen.core.network.source.interf.CollectionNetworkClient -import st.slex.csplashscreen.core.network.source.interf.PhotosNetworkClient -import st.slex.csplashscreen.core.network.source.interf.SearchPhotosNetworkSource -import st.slex.csplashscreen.core.network.source.interf.TopicsNetworkSource -import st.slex.csplashscreen.core.network.source.interf.UserNetworkSource - -interface NetworkClientApi { - - val collectionsClient: CollectionNetworkClient - - val photosClient: PhotosNetworkClient - - val searchClient: SearchPhotosNetworkSource - - val topicsClient: TopicsNetworkSource - - val userClient: UserNetworkSource -} \ No newline at end of file diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientComponent.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientComponent.kt deleted file mode 100644 index 97bd5abf..00000000 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkClientComponent.kt +++ /dev/null @@ -1,19 +0,0 @@ -package st.slex.csplashscreen.core.network.di - -import dagger.Component -import javax.inject.Singleton - -@Component( - modules = [NetworkClientModule::class], - dependencies = [NetworkDependencies::class] -) -@Singleton -interface NetworkClientComponent : NetworkClientApi { - - @Component.Factory - interface Factory { - - fun create(dependencies: NetworkDependencies): NetworkClientApi - } -} - diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependencies.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependencies.kt deleted file mode 100644 index 6bfcde52..00000000 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependencies.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.network.di - -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher - -interface NetworkDependencies { - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependenciesComponent.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependenciesComponent.kt deleted file mode 100644 index cbd3beab..00000000 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/di/NetworkDependenciesComponent.kt +++ /dev/null @@ -1,16 +0,0 @@ -package st.slex.csplashscreen.core.network.di - -import dagger.Component -import st.slex.csplashscreen.core.core.api.AppApi -import javax.inject.Singleton - -@Singleton -@Component(dependencies = [AppApi::class]) -interface NetworkDependenciesComponent : NetworkDependencies { - - @Component.Factory - interface Factory { - - fun create(appApi: AppApi): NetworkDependencies - } -} \ No newline at end of file diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/CollectionNetworkClientImpl.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/CollectionNetworkClientImpl.kt index 0ed486a9..16ea4d2b 100644 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/CollectionNetworkClientImpl.kt +++ b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/CollectionNetworkClientImpl.kt @@ -10,11 +10,8 @@ import st.slex.csplashscreen.core.network.utils.ServiceConstants.PARAMETER_PAGE import st.slex.csplashscreen.core.network.utils.ServiceConstants.PARAMETER_PAGE_SIZE import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_COLLECTIONS import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_USERS -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class CollectionNetworkClientImpl @Inject constructor( +class CollectionNetworkClientImpl( private val client: NetworkClient ) : CollectionNetworkClient { diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/PhotosNetworkClientImpl.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/PhotosNetworkClientImpl.kt index 987e17a7..221a489d 100644 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/PhotosNetworkClientImpl.kt +++ b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/PhotosNetworkClientImpl.kt @@ -15,14 +15,9 @@ import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_LIKES import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_PHOTOS import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_TOPICS import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_USERS -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.collections.List -import kotlin.collections.mutableMapOf import kotlin.collections.set -@Singleton -class PhotosNetworkClientImpl @Inject constructor( +class PhotosNetworkClientImpl( private val client: NetworkClient ) : PhotosNetworkClient { diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/SearchPhotosNetworkSourceImpl.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/SearchPhotosNetworkSourceImpl.kt index b6c0a60f..2063b7a5 100644 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/SearchPhotosNetworkSourceImpl.kt +++ b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/SearchPhotosNetworkSourceImpl.kt @@ -11,11 +11,8 @@ import st.slex.csplashscreen.core.network.utils.ServiceConstants.PARAMETER_PAGE_ import st.slex.csplashscreen.core.network.utils.ServiceConstants.PARAMETER_QUERY import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_PHOTOS import st.slex.csplashscreen.core.network.utils.ServiceConstants.PATH_SEARCH -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class SearchPhotosNetworkSourceImpl @Inject constructor( +class SearchPhotosNetworkSourceImpl( private val client: NetworkClient ) : SearchPhotosNetworkSource { diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/TopicsNetworkSourceImpl.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/TopicsNetworkSourceImpl.kt index 76431f73..0cd450a8 100644 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/TopicsNetworkSourceImpl.kt +++ b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/TopicsNetworkSourceImpl.kt @@ -9,11 +9,8 @@ import st.slex.csplashscreen.core.network.source.interf.TopicsNetworkSource import st.slex.csplashscreen.core.network.utils.ServiceConstants import st.slex.csplashscreen.core.network.utils.ServiceConstants.PARAMETER_PAGE import st.slex.csplashscreen.core.network.utils.ServiceConstants.PARAMETER_PAGE_SIZE -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class TopicsNetworkSourceImpl @Inject constructor( +class TopicsNetworkSourceImpl( private val client: NetworkClient ) : TopicsNetworkSource { diff --git a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/UserNetworkSourceImpl.kt b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/UserNetworkSourceImpl.kt index 4b129397..d96695dc 100644 --- a/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/UserNetworkSourceImpl.kt +++ b/core/network/src/main/java/st/slex/csplashscreen/core/network/source/impl/UserNetworkSourceImpl.kt @@ -6,11 +6,8 @@ import st.slex.csplashscreen.core.network.client.get import st.slex.csplashscreen.core.network.model.remote.user.RemoteUserModel import st.slex.csplashscreen.core.network.source.interf.UserNetworkSource import st.slex.csplashscreen.core.network.utils.ServiceConstants -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class UserNetworkSourceImpl @Inject constructor( +class UserNetworkSourceImpl( private val client: NetworkClient ) : UserNetworkSource { diff --git a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/data/PhotosRepositoryImpl.kt b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/data/PhotosRepositoryImpl.kt index 6d61ad26..a721fc48 100644 --- a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/data/PhotosRepositoryImpl.kt +++ b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/data/PhotosRepositoryImpl.kt @@ -4,11 +4,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import st.slex.csplashscreen.core.network.model.remote.image.RemoteImageModel import st.slex.csplashscreen.core.network.source.interf.PhotosNetworkClient -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class PhotosRepositoryImpl @Inject constructor( +class PhotosRepositoryImpl( private val client: PhotosNetworkClient ) : PhotosRepository { diff --git a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/CorePhotosComponent.kt b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/CorePhotosComponent.kt deleted file mode 100644 index b60f82bd..00000000 --- a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/CorePhotosComponent.kt +++ /dev/null @@ -1,29 +0,0 @@ -package st.slex.csplashscreen.core.photos.di - -import dagger.Component -import st.slex.csplashscreen.core.network.di.NetworkClientApi -import javax.inject.Singleton - -@Component( - dependencies = [PhotosDependencies::class], - modules = [ModuleCorePhotos::class] -) -@Singleton -interface CorePhotosComponent : PhotosApi { - - @Component.Factory - interface Factory { - - fun create(dependencies: PhotosDependencies): PhotosApi - } - - @Component(dependencies = [NetworkClientApi::class]) - interface PhotosDependenciesComponent : PhotosDependencies { - - @Component.Factory - interface Factory { - - fun create(networkClientApi: NetworkClientApi): PhotosDependencies - } - } -} \ No newline at end of file diff --git a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/ModuleCorePhotos.kt b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/ModuleCorePhotos.kt index 0363a492..ccbbe83e 100644 --- a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/ModuleCorePhotos.kt +++ b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/ModuleCorePhotos.kt @@ -1,15 +1,11 @@ package st.slex.csplashscreen.core.photos.di -import dagger.Binds -import dagger.Module +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module import st.slex.csplashscreen.core.photos.data.PhotosRepository import st.slex.csplashscreen.core.photos.data.PhotosRepositoryImpl -import javax.inject.Singleton -@Module -interface ModuleCorePhotos { - - @Binds - @Singleton - fun bindsPhotosRepository(impl: PhotosRepositoryImpl): PhotosRepository +val moduleCorePhotos = module { + singleOf(::PhotosRepositoryImpl) { bind() } } \ No newline at end of file diff --git a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApi.kt b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApi.kt deleted file mode 100644 index d96b1670..00000000 --- a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApi.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.photos.di - -import st.slex.csplashscreen.core.photos.data.PhotosRepository - -interface PhotosApi { - - val repository: PhotosRepository -} \ No newline at end of file diff --git a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApiBuilder.kt b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApiBuilder.kt deleted file mode 100644 index c66b52dd..00000000 --- a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosApiBuilder.kt +++ /dev/null @@ -1,19 +0,0 @@ -package st.slex.csplashscreen.core.photos.di - -import st.slex.csplashscreen.core.core.api.AppApi -import st.slex.csplashscreen.core.network.di.NetworkApiBuilder - -object PhotosApiBuilder { - - fun build( - appApi: AppApi - ): PhotosApi = DaggerCorePhotosComponent - .factory() - .create( - dependencies = DaggerCorePhotosComponent_PhotosDependenciesComponent - .factory() - .create( - networkClientApi = NetworkApiBuilder.build(appApi) - ) - ) -} \ No newline at end of file diff --git a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosDependencies.kt b/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosDependencies.kt deleted file mode 100644 index 2afe5a34..00000000 --- a/core/photos/src/main/java/st/slex/csplashscreen/core/photos/di/PhotosDependencies.kt +++ /dev/null @@ -1,8 +0,0 @@ -package st.slex.csplashscreen.core.photos.di - -import st.slex.csplashscreen.core.network.source.interf.PhotosNetworkClient - -interface PhotosDependencies { - - val photosClient: PhotosNetworkClient -} \ No newline at end of file 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 718b854b..59651c2c 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 @@ -1,62 +1,14 @@ package st.slex.csplashscreen.core.ui.base import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.viewmodel.compose.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.ui.di.MainUiProvider -import st.slex.csplashscreen.core.ui.di.builder.Feature -import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder -@Composable -inline fun daggerViewModel( - key: String? = null, - crossinline factory: () -> ViewModelProvider.Factory -): T = viewModel( - modelClass = T::class.java, - key = key, - factory = factory() -) - -@Composable -inline fun setupComponent( - builder: FeatureBuilder, - key: String? = null, - featureKey: Any? = null -): VM { - val context = LocalContext.current - val mainUiApi = checkNotNull(context as? MainUiProvider) { - "MainUiProvider is not implemented in $context" - }.api - - DisposableEffect(Unit) { - builder.setup( - mainUiApi = mainUiApi, - key = featureKey - ) - onDispose { - builder.clear() - } - } - - return daggerViewModel(key) { - builder - .build( - mainUiApi = mainUiApi, - key = featureKey - ) - .viewModelFactory - } -} - -inline fun NavGraphBuilder.createScreen( +inline fun NavGraphBuilder.createScreen( appDestination: AppDestination, - featureBuilder: FeatureBuilder, crossinline content: @Composable (VM, List) -> Unit ) { composable( @@ -64,8 +16,7 @@ inline fun NavGraphBuilder.createS arguments = appDestination.composableArguments ) { navBackStackEntry -> val arguments = appDestination.parseArguments(navBackStackEntry) - val viewModel: VM = setupComponent( - builder = featureBuilder, + val viewModel: VM = koinViewModel( key = arguments.hashCode().toString() ) /*TODO maybe good point to make instance of state, event, action here diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/ViewModelFactory.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/ViewModelFactory.kt deleted file mode 100644 index f7bf08a7..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/base/ViewModelFactory.kt +++ /dev/null @@ -1,25 +0,0 @@ -package st.slex.csplashscreen.core.ui.base - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import javax.inject.Inject -import javax.inject.Provider - -class ViewModelFactory @Inject constructor( - private val viewModelMap: Map, @JvmSuppressWildcards Provider> -) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create( - modelClass: Class - ): T = viewModelMap - .getOrElse(modelClass) { - viewModelMap.firstNotNullOfOrNull { entry -> - entry.takeIf { - modelClass.isAssignableFrom(it.key) - }?.value - } - } - ?.get() as? T? - ?: throw IllegalArgumentException("Unknown model class $modelClass") -} \ No newline at end of file diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiApi.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiApi.kt deleted file mode 100644 index 9024e077..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiApi.kt +++ /dev/null @@ -1,6 +0,0 @@ -package st.slex.csplashscreen.core.ui.di - -import st.slex.csplashscreen.core.core.api.AppApi -import st.slex.csplashscreen.core.navigation.di.NavigationApi - -interface MainUiApi : AppApi, NavigationApi diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiProvider.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiProvider.kt deleted file mode 100644 index 9edb4aa8..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/MainUiProvider.kt +++ /dev/null @@ -1,6 +0,0 @@ -package st.slex.csplashscreen.core.ui.di - -interface MainUiProvider { - - val api: MainUiApi -} diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/ViewModelKey.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/ViewModelKey.kt deleted file mode 100644 index f6df7c41..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/ViewModelKey.kt +++ /dev/null @@ -1,14 +0,0 @@ -package st.slex.csplashscreen.core.ui.di - -import androidx.lifecycle.ViewModel -import dagger.MapKey -import kotlin.reflect.KClass - -@MapKey -@Retention(AnnotationRetention.RUNTIME) -@Target( - AnnotationTarget.FUNCTION, - AnnotationTarget.PROPERTY_GETTER, - AnnotationTarget.PROPERTY_SETTER -) -annotation class ViewModelKey(val value: KClass) \ No newline at end of file diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/Feature.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/Feature.kt deleted file mode 100644 index 81d05af0..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/Feature.kt +++ /dev/null @@ -1,12 +0,0 @@ -package st.slex.csplashscreen.core.ui.di.builder - -import androidx.lifecycle.ViewModelProvider - -interface Feature { - - /** - * This property is used to get the ViewModelFactory of the feature - * @return ViewModelProvider.Factory - * */ - val viewModelFactory: ViewModelProvider.Factory -} diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureBuilder.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureBuilder.kt deleted file mode 100644 index f72c1912..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureBuilder.kt +++ /dev/null @@ -1,55 +0,0 @@ -package st.slex.csplashscreen.core.ui.di.builder - -import st.slex.csplashscreen.core.ui.di.MainUiApi - -abstract class FeatureBuilder { - - /** This property is used to get the key of the feature */ - abstract val key: Any - - /** - * This method is used to create a new instance of the feature - * @param mainUiApi - the mainUiApi instance - */ - abstract fun create(mainUiApi: MainUiApi): F - - /** - * This method is used to get the feature from the FeatureCollector - * or create a new instance of the feature and add it to the FeatureCollector - * @param key - the key of the feature - * @param mainUiApi - the mainUiApi instance - */ - inline fun build( - mainUiApi: MainUiApi, - key: Any? = null, - ): T = FeatureCollector.get(keyBuilder(key)) as? T - ?: setup(mainUiApi, key) as T - - /** - * This method is used to create a new instance of the feature - * and add it to the FeatureCollector - * @param key - the key of the feature - * @param mainUiApi - the mainUiApi instance - */ - fun setup( - mainUiApi: MainUiApi, - key: Any? = null, - ): F = create(mainUiApi).also { createdFeature -> - FeatureCollector.add(keyBuilder(key), createdFeature) - } - - /** - * This method is used to remove the feature from the FeatureCollector - */ - fun clear() { - FeatureCollector.remove(key) - } - - /** - * This method is used to get the key of the feature - * @param extraKey - the extra key of the feature - */ - fun keyBuilder( - extraKey: Any? - ): Any = extraKey?.let { "$key:$it" } ?: key -} diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureCollector.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureCollector.kt deleted file mode 100644 index 3d92371b..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/di/builder/FeatureCollector.kt +++ /dev/null @@ -1,16 +0,0 @@ -package st.slex.csplashscreen.core.ui.di.builder - -object FeatureCollector { - - private val features: MutableMap = mutableMapOf() - - fun get(key: Any): Feature? = features[key] - - internal fun add(key: Any, feature: Feature) { - features[key] = feature - } - - internal fun remove(key: Any) { - features.remove(key) - } -} \ No newline at end of file diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt deleted file mode 100644 index defa4126..00000000 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt +++ /dev/null @@ -1,109 +0,0 @@ -package st.slex.csplashscreen.core.ui.mvi - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import androidx.paging.Pager -import androidx.paging.PagingData -import androidx.paging.cachedIn -import androidx.paging.map -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import st.slex.csplashscreen.core.core.Logger -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.ui.mvi.Store.Action -import st.slex.csplashscreen.core.ui.mvi.Store.Event -import st.slex.csplashscreen.core.ui.mvi.Store.Navigation -import st.slex.csplashscreen.core.ui.mvi.Store.State - -abstract class BaseViewModel( - private val router: Router, - private val appDispatcher: AppDispatcher, - initialState: S -) : ViewModel() { - - private val _state: MutableStateFlow = MutableStateFlow(initialState) - val state: StateFlow - get() = _state.asStateFlow() - - val event: MutableSharedFlow = MutableSharedFlow() - - abstract fun sendAction(action: A) - - fun sendEvent(event: E) { - viewModelScope.launch(appDispatcher.default) { - this@BaseViewModel.event.emit(event) - } - } - - protected fun navigate(event: N) { - router(event) - } - - protected fun updateState(update: (S) -> S) { - _state.update(update) - } - - protected fun Pager.state( - transform: suspend (value: T) -> R - ): StateFlow> = this - .flow - .map { pagingData -> pagingData.map(transform) } - .state() - - protected fun Flow>.state(): StateFlow> = this - .flowOn(appDispatcher.default) - .cachedIn(viewModelScope) - .stateIn( - initialValue = PagingData.empty(), - scope = viewModelScope, - started = SharingStarted.Lazily - ) - - protected fun launch( - block: suspend CoroutineScope.() -> Unit - ): Job = viewModelScope.launch( - context = appDispatcher.default, - block = block - ) - - protected fun launchCatching( - block: suspend CoroutineScope.() -> T, - onFailure: suspend (Throwable) -> Unit = {}, - onSuccess: (T) -> Unit, - ): Job = viewModelScope.launch(appDispatcher.default) { - runCatching { - block() - } - .onSuccess(onSuccess) - .onFailure { error -> - onFailure(error) - Logger.exception(error) - } - } - - protected fun Flow.launch( - onError: suspend (cause: Throwable) -> Unit = {}, - each: suspend (T) -> Unit - ): Job = this - .flowOn(appDispatcher.default) - .catch { error -> - onError(error) - Logger.exception(error) - } - .onEach(each) - .launchIn(viewModelScope) -} \ No newline at end of file diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Router.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Router.kt index 4763faa2..26b23bed 100644 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Router.kt +++ b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/Router.kt @@ -1,5 +1,5 @@ package st.slex.csplashscreen.core.ui.mvi -fun interface Router { +fun interface Router { operator fun invoke(event: E) } \ 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 a3117d6b..d1865ca4 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 @@ -1,12 +1,109 @@ package st.slex.csplashscreen.core.ui.mvi -interface Store { +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.paging.Pager +import androidx.paging.PagingData +import androidx.paging.cachedIn +import androidx.paging.map +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import st.slex.csplashscreen.core.core.Logger +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher +import st.slex.csplashscreen.core.ui.mvi.StoreComponent.Action +import st.slex.csplashscreen.core.ui.mvi.StoreComponent.Event +import st.slex.csplashscreen.core.ui.mvi.StoreComponent.Navigation +import st.slex.csplashscreen.core.ui.mvi.StoreComponent.State - interface State +abstract class Store( + private val router: Router, + private val appDispatcher: AppDispatcher, + initialState: S +) : ViewModel() { - interface Event + private val _state: MutableStateFlow = MutableStateFlow(initialState) + val state: StateFlow + get() = _state.asStateFlow() - interface Navigation + val event: MutableSharedFlow = MutableSharedFlow() - interface Action -} + abstract fun sendAction(action: A) + + fun sendEvent(event: E) { + viewModelScope.launch(appDispatcher.default) { + this@Store.event.emit(event) + } + } + + protected fun navigate(event: N) { + router(event) + } + + protected fun updateState(update: (S) -> S) { + _state.update(update) + } + + protected fun Pager.state( + transform: suspend (value: T) -> R + ): StateFlow> = this + .flow + .map { pagingData -> pagingData.map(transform) } + .state() + + protected fun Flow>.state(): StateFlow> = this + .flowOn(appDispatcher.default) + .cachedIn(viewModelScope) + .stateIn( + initialValue = PagingData.empty(), + scope = viewModelScope, + started = SharingStarted.Lazily + ) + + protected fun launch( + block: suspend CoroutineScope.() -> Unit + ): Job = viewModelScope.launch( + context = appDispatcher.default, + block = block + ) + + protected fun launchCatching( + block: suspend CoroutineScope.() -> T, + onFailure: suspend (Throwable) -> Unit = {}, + onSuccess: (T) -> Unit, + ): Job = viewModelScope.launch(appDispatcher.default) { + runCatching { + block() + } + .onSuccess(onSuccess) + .onFailure { error -> + onFailure(error) + Logger.exception(error) + } + } + + protected fun Flow.launch( + onError: suspend (cause: Throwable) -> Unit = {}, + each: suspend (T) -> Unit + ): Job = this + .flowOn(appDispatcher.default) + .catch { error -> + onError(error) + Logger.exception(error) + } + .onEach(each) + .launchIn(viewModelScope) +} \ No newline at end of file diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/StoreComponent.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/StoreComponent.kt new file mode 100644 index 00000000..82a9fe28 --- /dev/null +++ b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/StoreComponent.kt @@ -0,0 +1,12 @@ +package st.slex.csplashscreen.core.ui.mvi + +interface StoreComponent { + + interface State + + interface Event + + interface Navigation + + interface Action +} diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/data/SingleCollectionRepositoryImpl.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/data/SingleCollectionRepositoryImpl.kt index 4617497a..a62f9581 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/data/SingleCollectionRepositoryImpl.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/data/SingleCollectionRepositoryImpl.kt @@ -4,9 +4,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import st.slex.csplashscreen.core.network.model.remote.image.RemoteImageModel import st.slex.csplashscreen.core.network.source.interf.PhotosNetworkClient -import javax.inject.Inject -class SingleCollectionRepositoryImpl @Inject constructor( +class SingleCollectionRepositoryImpl( private val source: PhotosNetworkClient ) : SingleCollectionRepository { diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/ModuleFeatureSingleCollection.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/ModuleFeatureSingleCollection.kt new file mode 100644 index 00000000..abb0ad4f --- /dev/null +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/ModuleFeatureSingleCollection.kt @@ -0,0 +1,20 @@ +package st.slex.csplashscreen.feature.collection.di + +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module +import st.slex.csplashscreen.feature.collection.data.SingleCollectionRepository +import st.slex.csplashscreen.feature.collection.data.SingleCollectionRepositoryImpl +import st.slex.csplashscreen.feature.collection.domain.SingleCollectionInteractor +import st.slex.csplashscreen.feature.collection.domain.SingleCollectionInteractorImpl +import st.slex.csplashscreen.feature.collection.navigation.SingleCollectionRouter +import st.slex.csplashscreen.feature.collection.navigation.SingleCollectionRouterImpl +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore + +val moduleFeatureSingleCollection = module { + factoryOf(::SingleCollectionRepositoryImpl) { bind() } + factoryOf(::SingleCollectionInteractorImpl) { bind() } + factoryOf(::SingleCollectionRouterImpl) { bind() } + viewModelOf(::SingleCollectionStore) +} \ No newline at end of file diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionBuilder.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionBuilder.kt deleted file mode 100644 index 5f33584f..00000000 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionBuilder.kt +++ /dev/null @@ -1,24 +0,0 @@ -package st.slex.csplashscreen.feature.collection.di - -import st.slex.csplashscreen.core.network.di.NetworkApiBuilder -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder - -object SingleCollectionBuilder : FeatureBuilder() { - - override val key: Any = "single-collection-feature" - - override fun create( - mainUiApi: MainUiApi - ): SingleCollectionComponent = - DaggerSingleCollectionComponent - .factory() - .create( - dependencies = DaggerSingleCollectionComponent_SingleCollectionDependenciesComponent - .factory() - .create( - mainUiApi = mainUiApi, - networkClientApi = NetworkApiBuilder.build(mainUiApi), - ) - ) -} diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionComponent.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionComponent.kt deleted file mode 100644 index 24a9c32a..00000000 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionComponent.kt +++ /dev/null @@ -1,40 +0,0 @@ -package st.slex.csplashscreen.feature.collection.di - -import dagger.Component -import st.slex.csplashscreen.core.network.di.NetworkClientApi -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.Feature - -@Component( - dependencies = [SingleCollectionDependencies::class], - modules = [SingleCollectionModule::class] -) -@SingleCollectionScope -interface SingleCollectionComponent : Feature { - - @Component.Factory - interface Factory { - fun create( - dependencies: SingleCollectionDependencies - ): SingleCollectionComponent - } - - @Component( - dependencies = [ - MainUiApi::class, - NetworkClientApi::class, - ] - ) - @SingleCollectionScope - interface SingleCollectionDependenciesComponent : SingleCollectionDependencies { - - @Component.Factory - interface Factory { - - fun create( - mainUiApi: MainUiApi, - networkClientApi: NetworkClientApi, - ): SingleCollectionDependencies - } - } -} \ No newline at end of file diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionDependencies.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionDependencies.kt deleted file mode 100644 index d492cd78..00000000 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionDependencies.kt +++ /dev/null @@ -1,14 +0,0 @@ -package st.slex.csplashscreen.feature.collection.di - -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.navigation.navigator.Navigator -import st.slex.csplashscreen.core.network.source.interf.PhotosNetworkClient - -interface SingleCollectionDependencies { - - val client: PhotosNetworkClient - - val navigator: Navigator - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionModule.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionModule.kt deleted file mode 100644 index b051bfd8..00000000 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionModule.kt +++ /dev/null @@ -1,41 +0,0 @@ -package st.slex.csplashscreen.feature.collection.di - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import st.slex.csplashscreen.core.ui.base.ViewModelFactory -import st.slex.csplashscreen.core.ui.di.ViewModelKey -import st.slex.csplashscreen.feature.collection.data.SingleCollectionRepository -import st.slex.csplashscreen.feature.collection.data.SingleCollectionRepositoryImpl -import st.slex.csplashscreen.feature.collection.domain.SingleCollectionInteractor -import st.slex.csplashscreen.feature.collection.domain.SingleCollectionInteractorImpl -import st.slex.csplashscreen.feature.collection.navigation.SingleCollectionRouter -import st.slex.csplashscreen.feature.collection.navigation.SingleCollectionRouterImpl -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionViewModel - -@Module -interface SingleCollectionModule { - - @Binds - @SingleCollectionScope - fun bindsRepository(impl: SingleCollectionRepositoryImpl): SingleCollectionRepository - - @Binds - @SingleCollectionScope - fun bindsInteractor(impl: SingleCollectionInteractorImpl): SingleCollectionInteractor - - @Binds - @SingleCollectionScope - fun bindRouter(impl: SingleCollectionRouterImpl): SingleCollectionRouter - - @Binds - @IntoMap - @ViewModelKey(SingleCollectionViewModel::class) - fun bindsViewModel(impl: SingleCollectionViewModel): ViewModel - - @Binds - @SingleCollectionScope - fun bindsFactory(impl: ViewModelFactory): ViewModelProvider.Factory -} \ No newline at end of file diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionScope.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionScope.kt deleted file mode 100644 index 325d1938..00000000 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/di/SingleCollectionScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package st.slex.csplashscreen.feature.collection.di - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class SingleCollectionScope diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/domain/SingleCollectionInteractorImpl.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/domain/SingleCollectionInteractorImpl.kt index 1401a2f3..c94a295e 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/domain/SingleCollectionInteractorImpl.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/domain/SingleCollectionInteractorImpl.kt @@ -3,9 +3,8 @@ package st.slex.csplashscreen.feature.collection.domain import st.slex.csplashscreen.core.network.model.toDomain import st.slex.csplashscreen.core.network.model.ui.ImageModel import st.slex.csplashscreen.feature.collection.data.SingleCollectionRepository -import javax.inject.Inject -class SingleCollectionInteractorImpl @Inject constructor( +class SingleCollectionInteractorImpl( private val repository: SingleCollectionRepository ) : SingleCollectionInteractor { 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 cdc0868b..1a84e6be 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 @@ -10,26 +10,22 @@ 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.ui.utils.CollectAsEvent -import st.slex.csplashscreen.feature.collection.di.SingleCollectionBuilder import st.slex.csplashscreen.feature.collection.ui.CollectionScreen -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore.Action -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionViewModel +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.Action fun NavGraphBuilder.singleCollectionGraph( modifier: Modifier = Modifier, ) { - createScreen( - appDestination = AppDestination.COLLECTION, - featureBuilder = SingleCollectionBuilder - ) { viewModel: SingleCollectionViewModel, args -> + createScreen(AppDestination.COLLECTION) { store: SingleCollectionStore, args -> val arguments = args.first().let(AppArguments::CollectionScreen) - val photos = remember { viewModel.state.mapState { it.photos } }.collectAsLazyPagingItems() + val photos = remember { store.state.mapState { it.photos } }.collectAsLazyPagingItems() LaunchedEffect(Unit) { - viewModel.sendAction(Action.Init(arguments.collectionId)) + store.sendAction(Action.Init(arguments.collectionId)) } - viewModel.event.CollectAsEvent { event -> + store.event.CollectAsEvent { event -> // TODO NOT IMPLEMENTED YET } @@ -38,12 +34,12 @@ fun NavGraphBuilder.singleCollectionGraph( photos = photos, onImageClick = remember { { uuid -> - viewModel.sendAction(Action.OnImageClick(uuid)) + store.sendAction(Action.OnImageClick(uuid)) } }, onProfileClick = remember { { username -> - viewModel.sendAction(Action.OnProfileClick(username)) + store.sendAction(Action.OnProfileClick(username)) } } ) diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouter.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouter.kt index d8a92033..fb4e1212 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouter.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionRouter.kt @@ -1,6 +1,6 @@ package st.slex.csplashscreen.feature.collection.navigation import st.slex.csplashscreen.core.ui.mvi.Router -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore.Navigation +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.Navigation interface SingleCollectionRouter : Router \ No newline at end of file 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 e23a9d49..f67e8dea 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 @@ -2,10 +2,9 @@ package st.slex.csplashscreen.feature.collection.navigation 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.SingleCollectionStore.Navigation -import javax.inject.Inject +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.Navigation -class SingleCollectionRouterImpl @Inject constructor( +class SingleCollectionRouterImpl( private val navigator: Navigator ) : SingleCollectionRouter { diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt index 4e722cb8..80220961 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt @@ -1,58 +1,94 @@ package st.slex.csplashscreen.feature.collection.ui.presenter -import androidx.compose.runtime.Stable +import androidx.paging.Pager +import androidx.paging.PagingConfig import androidx.paging.PagingData +import androidx.paging.map +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher +import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.photos.ui.model.toPresentation import st.slex.csplashscreen.core.ui.mvi.Store +import st.slex.csplashscreen.core.ui.paging.PagingSource +import st.slex.csplashscreen.feature.collection.domain.SingleCollectionInteractor +import st.slex.csplashscreen.feature.collection.navigation.SingleCollectionRouter +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.Action +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.Event +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.Navigation +import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStoreComponent.State -interface SingleCollectionStore { - - @Stable - data class State( - val photos: PagingData, - val collectionId: String, - ) : Store.State { - companion object { - val INITIAL = State( - photos = PagingData.empty(), - collectionId = "" - ) +class SingleCollectionStore( + private val interactor: SingleCollectionInteractor, + appDispatcher: AppDispatcher, + router: SingleCollectionRouter +) : Store( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { + + override fun sendAction(action: Action) { + when (action) { + is Action.Init -> actionInit(action) + is Action.OnProfileClick -> actionProfileClick(action) + is Action.OnImageClick -> actionImageClick(action) } } - @Stable - sealed interface Event : Store.Event - - @Stable - sealed interface Navigation : Store.Navigation { + private fun actionInit(action: Action.Init) { + updateState { currentState -> + currentState.copy( + collectionId = action.collectionId + ) + } + allPhotos.launch { pagingData -> + updateState { currentState -> + currentState.copy( + photos = pagingData + ) + } + } + } - @Stable - data class Profile( - val username: String - ) : Navigation + @OptIn(ExperimentalCoroutinesApi::class) + private val allPhotos: StateFlow> + get() = state + .mapState { currentState -> + currentState.collectionId + } + .filter { it.isNotBlank() } + .flatMapLatest { collectionId -> + Pager(pagingConfig) { + PagingSource { page, pageSize -> + interactor.getPhotos( + uuid = collectionId, + page = page, + pageSize = pageSize + ) + } + }.flow + } + .map { pagingData -> pagingData.map { it.toPresentation() } } + .state() - @Stable - data class ImageDetail( - val uuid: String - ) : Navigation + private fun actionProfileClick(action: Action.OnProfileClick) { + navigate(Navigation.Profile(action.username)) } - @Stable - sealed interface Action : Store.Action { - - @Stable - data class Init( - val collectionId: String - ) : Action + private fun actionImageClick(action: Action.OnImageClick) { + navigate(Navigation.ImageDetail(action.uuid)) + } - @Stable - data class OnImageClick( - val uuid: String - ) : Action + companion object { - @Stable - data class OnProfileClick( - val username: String - ) : Action + private val pagingConfig = PagingConfig( + pageSize = 5, + enablePlaceholders = false + ) } } \ No newline at end of file diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStoreComponent.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStoreComponent.kt new file mode 100644 index 00000000..61a88c51 --- /dev/null +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStoreComponent.kt @@ -0,0 +1,58 @@ +package st.slex.csplashscreen.feature.collection.ui.presenter + +import androidx.compose.runtime.Stable +import androidx.paging.PagingData +import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.ui.mvi.StoreComponent + +interface SingleCollectionStoreComponent { + + @Stable + data class State( + val photos: PagingData, + val collectionId: String, + ) : StoreComponent.State { + companion object { + val INITIAL = State( + photos = PagingData.empty(), + collectionId = "" + ) + } + } + + @Stable + sealed interface Event : StoreComponent.Event + + @Stable + sealed interface Navigation : StoreComponent.Navigation { + + @Stable + data class Profile( + val username: String + ) : Navigation + + @Stable + data class ImageDetail( + val uuid: String + ) : Navigation + } + + @Stable + sealed interface Action : StoreComponent.Action { + + @Stable + data class Init( + val collectionId: String + ) : Action + + @Stable + data class OnImageClick( + val uuid: String + ) : Action + + @Stable + data class OnProfileClick( + val username: String + ) : Action + } +} \ No newline at end of file diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt deleted file mode 100644 index 393aa8b7..00000000 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt +++ /dev/null @@ -1,95 +0,0 @@ -package st.slex.csplashscreen.feature.collection.ui.presenter - -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingData -import androidx.paging.map -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.map -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState -import st.slex.csplashscreen.core.photos.ui.model.PhotoModel -import st.slex.csplashscreen.core.photos.ui.model.toPresentation -import st.slex.csplashscreen.core.ui.mvi.BaseViewModel -import st.slex.csplashscreen.core.ui.paging.PagingSource -import st.slex.csplashscreen.feature.collection.domain.SingleCollectionInteractor -import st.slex.csplashscreen.feature.collection.navigation.SingleCollectionRouter -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore.Action -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore.Event -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore.Navigation -import st.slex.csplashscreen.feature.collection.ui.presenter.SingleCollectionStore.State -import javax.inject.Inject - -class SingleCollectionViewModel @Inject constructor( - private val interactor: SingleCollectionInteractor, - appDispatcher: AppDispatcher, - router: SingleCollectionRouter -) : BaseViewModel( - router = router, - appDispatcher = appDispatcher, - initialState = State.INITIAL -) { - - override fun sendAction(action: Action) { - when (action) { - is Action.Init -> actionInit(action) - is Action.OnProfileClick -> actionProfileClick(action) - is Action.OnImageClick -> actionImageClick(action) - } - } - - private fun actionInit(action: Action.Init) { - updateState { currentState -> - currentState.copy( - collectionId = action.collectionId - ) - } - allPhotos.launch { pagingData -> - updateState { currentState -> - currentState.copy( - photos = pagingData - ) - } - } - } - - @OptIn(ExperimentalCoroutinesApi::class) - private val allPhotos: StateFlow> - get() = state - .mapState { currentState -> - currentState.collectionId - } - .filter { it.isNotBlank() } - .flatMapLatest { collectionId -> - Pager(pagingConfig) { - PagingSource { page, pageSize -> - interactor.getPhotos( - uuid = collectionId, - page = page, - pageSize = pageSize - ) - } - }.flow - } - .map { pagingData -> pagingData.map { it.toPresentation() } } - .state() - - private fun actionProfileClick(action: Action.OnProfileClick) { - navigate(Navigation.Profile(action.username)) - } - - private fun actionImageClick(action: Action.OnImageClick) { - navigate(Navigation.ImageDetail(action.uuid)) - } - - companion object { - - private val pagingConfig = PagingConfig( - pageSize = 5, - enablePlaceholders = false - ) - } -} \ No newline at end of file diff --git a/feature/favourite/src/main/AndroidManifest.xml b/feature/favourite/src/main/AndroidManifest.xml index a5918e68..568741e5 100644 --- a/feature/favourite/src/main/AndroidManifest.xml +++ b/feature/favourite/src/main/AndroidManifest.xml @@ -1,4 +1,2 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponent.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponent.kt deleted file mode 100644 index 37f42da8..00000000 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponent.kt +++ /dev/null @@ -1,39 +0,0 @@ -package st.slex.csplashscreen.feature.favourite.di - -import dagger.Component -import st.slex.csplashscreen.core.favourite.di.FavouriteApi -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.Feature - -@Component( - dependencies = [FavouriteDependencies::class], - modules = [FavouriteModule::class] -) -@FavouriteScope -interface FavouriteComponent : Feature { - - @Component.Factory - interface Factory { - - fun create(dependencies: FavouriteDependencies): FavouriteComponent - } - - @Component( - dependencies = [ - MainUiApi::class, - FavouriteApi::class, - ] - ) - @FavouriteScope - interface FavouriteDependenciesComponent : FavouriteDependencies { - - @Component.Factory - interface Factory { - - fun create( - mainUiApi: MainUiApi, - favouriteApi: FavouriteApi, - ): FavouriteDependencies - } - } -} \ No newline at end of file diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponentBuilder.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponentBuilder.kt deleted file mode 100644 index b0940a44..00000000 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteComponentBuilder.kt +++ /dev/null @@ -1,22 +0,0 @@ -package st.slex.csplashscreen.feature.favourite.di - -import st.slex.csplashscreen.core.favourite.di.FavouriteApiBuilder -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder - -object FavouriteComponentBuilder : FeatureBuilder() { - - override val key: Any = "favorite-feature" - - override fun create( - mainUiApi: MainUiApi - ) = DaggerFavouriteComponent.factory() - .create( - dependencies = DaggerFavouriteComponent_FavouriteDependenciesComponent - .factory() - .create( - mainUiApi = mainUiApi, - favouriteApi = FavouriteApiBuilder.build(mainUiApi) - ) - ) -} diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteDependencies.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteDependencies.kt deleted file mode 100644 index 4c0292ae..00000000 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteDependencies.kt +++ /dev/null @@ -1,14 +0,0 @@ -package st.slex.csplashscreen.feature.favourite.di - -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.favourite.data.repository.FavouriteRepository -import st.slex.csplashscreen.core.navigation.navigator.Navigator - -interface FavouriteDependencies { - - val repository: FavouriteRepository - - val navigator: Navigator - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteModule.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteModule.kt deleted file mode 100644 index 5a8c11d1..00000000 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteModule.kt +++ /dev/null @@ -1,35 +0,0 @@ -package st.slex.csplashscreen.feature.favourite.di - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import st.slex.csplashscreen.core.ui.base.ViewModelFactory -import st.slex.csplashscreen.core.ui.di.ViewModelKey -import st.slex.csplashscreen.feature.favourite.domain.FavouriteInteractor -import st.slex.csplashscreen.feature.favourite.domain.FavouriteInteractorImpl -import st.slex.csplashscreen.feature.favourite.navigation.FavouriteRouter -import st.slex.csplashscreen.feature.favourite.navigation.FavouriteRouterImpl -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteViewModel - -@Module -interface FavouriteModule { - - @Binds - @FavouriteScope - fun bindsInteractor(impl: FavouriteInteractorImpl): FavouriteInteractor - - @Binds - @FavouriteScope - fun bindRouter(impl: FavouriteRouterImpl): FavouriteRouter - - @Binds - @FavouriteScope - fun bindFactory(impl: ViewModelFactory): ViewModelProvider.Factory - - @Binds - @IntoMap - @ViewModelKey(FavouriteViewModel::class) - fun bindsViewModel(impl: FavouriteViewModel): ViewModel -} \ No newline at end of file diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteScope.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteScope.kt deleted file mode 100644 index 2ea39c92..00000000 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/FavouriteScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package st.slex.csplashscreen.feature.favourite.di - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class FavouriteScope diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/ModuleFeatureFavourite.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/ModuleFeatureFavourite.kt new file mode 100644 index 00000000..9ae714a3 --- /dev/null +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/di/ModuleFeatureFavourite.kt @@ -0,0 +1,17 @@ +package st.slex.csplashscreen.feature.favourite.di + +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module +import st.slex.csplashscreen.feature.favourite.domain.FavouriteInteractor +import st.slex.csplashscreen.feature.favourite.domain.FavouriteInteractorImpl +import st.slex.csplashscreen.feature.favourite.navigation.FavouriteRouter +import st.slex.csplashscreen.feature.favourite.navigation.FavouriteRouterImpl +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore + +val moduleFeatureFavourite = module { + factoryOf(::FavouriteInteractorImpl) { bind() } + factoryOf(::FavouriteRouterImpl) { bind() } + viewModelOf(::FavouriteStore) +} \ No newline at end of file diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/domain/FavouriteInteractorImpl.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/domain/FavouriteInteractorImpl.kt index a6c218cb..bdc32da4 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/domain/FavouriteInteractorImpl.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/domain/FavouriteInteractorImpl.kt @@ -4,9 +4,8 @@ import androidx.paging.PagingData import kotlinx.coroutines.flow.Flow import st.slex.csplashscreen.core.favourite.data.repository.FavouriteRepository import st.slex.csplashscreen.core.photos.ui.model.PhotoModel -import javax.inject.Inject -class FavouriteInteractorImpl @Inject constructor( +class FavouriteInteractorImpl( private val favouriteRepository: FavouriteRepository ) : FavouriteInteractor { 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 611ec096..f704e73b 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 @@ -9,28 +9,26 @@ 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.ui.utils.CollectAsEvent -import st.slex.csplashscreen.feature.favourite.di.FavouriteComponentBuilder import st.slex.csplashscreen.feature.favourite.ui.FavouriteScreen -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore.Action -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteViewModel +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.Action fun NavGraphBuilder.favouriteGraph( modifier: Modifier = Modifier, ) { createScreen( appDestination = AppDestination.FAVOURITE, - featureBuilder = FavouriteComponentBuilder - ) { viewModel: FavouriteViewModel, _ -> + ) { store: FavouriteStore, _ -> LaunchedEffect(Unit) { - viewModel.sendAction(Action.Init) + store.sendAction(Action.Init) } val photos = remember { - viewModel.state.mapState { it.photos } + store.state.mapState { it.photos } }.collectAsLazyPagingItems() - viewModel.event.CollectAsEvent { event -> + store.event.CollectAsEvent { event -> // TODO NOT IMPLEMENTED YET } @@ -38,13 +36,13 @@ fun NavGraphBuilder.favouriteGraph( modifier = modifier, photos = photos, onUserClick = remember { - { username -> viewModel.sendAction(Action.OnUserClick(username)) } + { username -> store.sendAction(Action.OnUserClick(username)) } }, onImageClick = remember { - { uuid -> viewModel.sendAction(Action.OnImageClick(uuid)) } + { uuid -> store.sendAction(Action.OnImageClick(uuid)) } }, onGoToPhotosClick = remember { - { viewModel.sendAction(Action.GoToPhotosClick) } + { store.sendAction(Action.GoToPhotosClick) } } ) } diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouter.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouter.kt index 3f0cbf9f..54a2c622 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouter.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteRouter.kt @@ -1,6 +1,6 @@ package st.slex.csplashscreen.feature.favourite.navigation import st.slex.csplashscreen.core.ui.mvi.Router -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore.Navigation +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.Navigation interface FavouriteRouter : Router 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 fea9fd41..2bec3ecc 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 @@ -2,10 +2,9 @@ package st.slex.csplashscreen.feature.favourite.navigation import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore.Navigation -import javax.inject.Inject +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.Navigation -class FavouriteRouterImpl @Inject constructor( +class FavouriteRouterImpl( private val navigator: Navigator ) : FavouriteRouter { diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt index 73be1026..2352fc32 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt @@ -1,58 +1,56 @@ package st.slex.csplashscreen.feature.favourite.ui.presenter -import androidx.compose.runtime.Stable -import androidx.paging.PagingData -import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import kotlinx.coroutines.flow.map +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher import st.slex.csplashscreen.core.ui.mvi.Store - -interface FavouriteStore : Store { - - @Stable - data class State( - val photos: PagingData - ) : Store.State { - - companion object { - val INITIAL = State( - photos = PagingData.empty() - ) +import st.slex.csplashscreen.feature.favourite.domain.FavouriteInteractor +import st.slex.csplashscreen.feature.favourite.navigation.FavouriteRouter +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.Action +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.Event +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.Navigation +import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStoreComponent.State + +class FavouriteStore( + private val interactor: FavouriteInteractor, + appDispatcher: AppDispatcher, + router: FavouriteRouter +) : Store( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { + + override fun sendAction(action: Action) { + when (action) { + is Action.Init -> actionInit() + is Action.GoToPhotosClick -> actionGoHome() + is Action.OnImageClick -> actionImageClick(action) + is Action.OnUserClick -> actionUserClick(action) } } - @Stable - sealed interface Event : Store.Event - - @Stable - sealed interface Navigation : Store.Navigation { - - @Stable - data class User( - val username: String - ) : Navigation - - @Stable - data class Image( - val uuid: String - ) : Navigation - - @Stable - data object Home : Navigation + private fun actionInit() { + interactor.photos + .map { pagingData -> + pagingData + } + .state() + .launch { data -> + updateState { state -> + state.copy(photos = data) + } + } } - @Stable - sealed interface Action : Store.Action { - - data object Init : Action - - data class OnUserClick( - val username: String - ) : Action - - data class OnImageClick( - val uuid: String - ) : Action + private fun actionGoHome() { + navigate(Navigation.Home) + } - data object GoToPhotosClick : Action + private fun actionImageClick(action: Action.OnImageClick) { + navigate(Navigation.Image(action.uuid)) } -} + private fun actionUserClick(action: Action.OnUserClick) { + navigate(Navigation.User(action.username)) + } +} \ No newline at end of file diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStoreComponent.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStoreComponent.kt new file mode 100644 index 00000000..08fe16f9 --- /dev/null +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStoreComponent.kt @@ -0,0 +1,58 @@ +package st.slex.csplashscreen.feature.favourite.ui.presenter + +import androidx.compose.runtime.Stable +import androidx.paging.PagingData +import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.ui.mvi.StoreComponent + +interface FavouriteStoreComponent : StoreComponent { + + @Stable + data class State( + val photos: PagingData + ) : StoreComponent.State { + + companion object { + val INITIAL = State( + photos = PagingData.empty() + ) + } + } + + @Stable + sealed interface Event : StoreComponent.Event + + @Stable + sealed interface Navigation : StoreComponent.Navigation { + + @Stable + data class User( + val username: String + ) : Navigation + + @Stable + data class Image( + val uuid: String + ) : Navigation + + @Stable + data object Home : Navigation + } + + @Stable + sealed interface Action : StoreComponent.Action { + + data object Init : Action + + data class OnUserClick( + val username: String + ) : Action + + data class OnImageClick( + val uuid: String + ) : Action + + data object GoToPhotosClick : Action + } +} + diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt deleted file mode 100644 index 0eb8ceea..00000000 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt +++ /dev/null @@ -1,57 +0,0 @@ -package st.slex.csplashscreen.feature.favourite.ui.presenter - -import kotlinx.coroutines.flow.map -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.ui.mvi.BaseViewModel -import st.slex.csplashscreen.feature.favourite.domain.FavouriteInteractor -import st.slex.csplashscreen.feature.favourite.navigation.FavouriteRouter -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore.Action -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore.Event -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore.Navigation -import st.slex.csplashscreen.feature.favourite.ui.presenter.FavouriteStore.State -import javax.inject.Inject - -class FavouriteViewModel @Inject constructor( - private val interactor: FavouriteInteractor, - appDispatcher: AppDispatcher, - router: FavouriteRouter -) : BaseViewModel( - router = router, - appDispatcher = appDispatcher, - initialState = State.INITIAL -) { - - override fun sendAction(action: Action) { - when (action) { - is Action.Init -> actionInit() - is Action.GoToPhotosClick -> actionGoHome() - is Action.OnImageClick -> actionImageClick(action) - is Action.OnUserClick -> actionUserClick(action) - } - } - - private fun actionInit() { - interactor.photos - .map { pagingData -> - pagingData - } - .state() - .launch { data -> - updateState { state -> - state.copy(photos = data) - } - } - } - - private fun actionGoHome() { - navigate(Navigation.Home) - } - - private fun actionImageClick(action: Action.OnImageClick) { - navigate(Navigation.Image(action.uuid)) - } - - private fun actionUserClick(action: Action.OnUserClick) { - navigate(Navigation.User(action.username)) - } -} \ No newline at end of file diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponent.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponent.kt deleted file mode 100644 index f31a6016..00000000 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponent.kt +++ /dev/null @@ -1,41 +0,0 @@ -package st.slex.csplashscreen.feature.home.di - -import dagger.Component -import st.slex.csplashscreen.core.collection.di.CollectionApi -import st.slex.csplashscreen.core.photos.di.PhotosApi -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.Feature - -@Component( - dependencies = [HomeDependencies::class], - modules = [HomeModule::class] -) -@HomeScope -interface HomeComponent : Feature { - - @Component.Factory - interface Factory { - - fun create(dependencies: HomeDependencies): HomeComponent - } - - @Component( - dependencies = [ - MainUiApi::class, - CollectionApi::class, - PhotosApi::class - ] - ) - @HomeScope - interface HomeDependenciesComponent : HomeDependencies { - - @Component.Factory - interface Factory { - fun create( - mainUiApi: MainUiApi, - collectionApi: CollectionApi, - photosApi: PhotosApi - ): HomeDependencies - } - } -} \ No newline at end of file diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponentBuilder.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponentBuilder.kt deleted file mode 100644 index de23d1c0..00000000 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeComponentBuilder.kt +++ /dev/null @@ -1,25 +0,0 @@ -package st.slex.csplashscreen.feature.home.di - -import st.slex.csplashscreen.core.collection.di.CollectionApiBuilder -import st.slex.csplashscreen.core.photos.di.PhotosApiBuilder -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder - -object HomeComponentBuilder : FeatureBuilder() { - - override val key: Any = "home-feature" - - override fun create( - mainUiApi: MainUiApi - ) = DaggerHomeComponent - .factory() - .create( - dependencies = DaggerHomeComponent_HomeDependenciesComponent - .factory() - .create( - mainUiApi = mainUiApi, - collectionApi = CollectionApiBuilder.build(mainUiApi), - photosApi = PhotosApiBuilder.build(mainUiApi) - ) - ) -} diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeDependencies.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeDependencies.kt deleted file mode 100644 index ef53bdb7..00000000 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeDependencies.kt +++ /dev/null @@ -1,17 +0,0 @@ -package st.slex.csplashscreen.feature.home.di - -import st.slex.csplashscreen.core.collection.data.CollectionsRepository -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.navigation.navigator.Navigator -import st.slex.csplashscreen.core.photos.data.PhotosRepository - -interface HomeDependencies { - - val collectionRepository: CollectionsRepository - - val photosRepository: PhotosRepository - - val navigator: Navigator - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeModule.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeModule.kt deleted file mode 100644 index fd99acfb..00000000 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeModule.kt +++ /dev/null @@ -1,35 +0,0 @@ -package st.slex.csplashscreen.feature.home.di - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import st.slex.csplashscreen.core.ui.base.ViewModelFactory -import st.slex.csplashscreen.core.ui.di.ViewModelKey -import st.slex.csplashscreen.feature.home.domain.HomeInteractor -import st.slex.csplashscreen.feature.home.domain.HomeInteractorImpl -import st.slex.csplashscreen.feature.home.navigation.HomeRouter -import st.slex.csplashscreen.feature.home.navigation.HomeRouterImpl -import st.slex.csplashscreen.feature.home.ui.presenter.HomeViewModel - -@Module -interface HomeModule { - - @Binds - @HomeScope - fun bindsInteractor(impl: HomeInteractorImpl): HomeInteractor - - @Binds - @HomeScope - fun bindsRouter(impl: HomeRouterImpl): HomeRouter - - @Binds - @HomeScope - fun bindsViewModelFactory(impl: ViewModelFactory): ViewModelProvider.Factory - - @Binds - @IntoMap - @ViewModelKey(HomeViewModel::class) - fun bindsViewModel(impl: HomeViewModel): ViewModel -} \ No newline at end of file diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeScope.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeScope.kt deleted file mode 100644 index ccfaaa00..00000000 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/HomeScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package st.slex.csplashscreen.feature.home.di - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class HomeScope diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/ModuleFeatureHome.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/ModuleFeatureHome.kt new file mode 100644 index 00000000..91ec0bb5 --- /dev/null +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/di/ModuleFeatureHome.kt @@ -0,0 +1,17 @@ +package st.slex.csplashscreen.feature.home.di + +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module +import st.slex.csplashscreen.feature.home.domain.HomeInteractor +import st.slex.csplashscreen.feature.home.domain.HomeInteractorImpl +import st.slex.csplashscreen.feature.home.navigation.HomeRouter +import st.slex.csplashscreen.feature.home.navigation.HomeRouterImpl +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore + +val moduleFeatureHome = module { + factoryOf(::HomeInteractorImpl) { bind() } + factoryOf(::HomeRouterImpl) { bind() } + viewModelOf(::HomeStore) +} \ No newline at end of file diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/domain/HomeInteractorImpl.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/domain/HomeInteractorImpl.kt index 11360095..8f70db53 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/domain/HomeInteractorImpl.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/domain/HomeInteractorImpl.kt @@ -6,9 +6,8 @@ import st.slex.csplashscreen.core.network.model.toDomain import st.slex.csplashscreen.core.network.model.ui.CollectionDomainModel import st.slex.csplashscreen.core.network.model.ui.ImageModel import st.slex.csplashscreen.core.photos.data.PhotosRepository -import javax.inject.Inject -class HomeInteractorImpl @Inject constructor( +class HomeInteractorImpl( private val photosRepository: PhotosRepository, private val collectionsRepository: CollectionsRepository ) : HomeInteractor { 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 6b782b92..cac4508c 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 @@ -9,32 +9,28 @@ 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.ui.utils.CollectAsEvent -import st.slex.csplashscreen.feature.home.di.HomeComponentBuilder import st.slex.csplashscreen.feature.home.ui.MainScreen -import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore.Action -import st.slex.csplashscreen.feature.home.ui.presenter.HomeViewModel +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.Action fun NavGraphBuilder.homeGraph( modifier: Modifier = Modifier, ) { - createScreen( - appDestination = AppDestination.HOME, - featureBuilder = HomeComponentBuilder - ) { viewModel: HomeViewModel, _ -> + createScreen(AppDestination.HOME) { store: HomeStore, _ -> LaunchedEffect(Unit) { - viewModel.sendAction(Action.Init) + store.sendAction(Action.Init) } val collections = remember { - viewModel.state.mapState { it.collections } + store.state.mapState { it.collections } }.collectAsLazyPagingItems() val photos = remember { - viewModel.state.mapState { it.photos } + store.state.mapState { it.photos } }.collectAsLazyPagingItems() - viewModel.event.CollectAsEvent { event -> + store.event.CollectAsEvent { event -> // TODO NOT IMPLEMENTED YET } @@ -42,17 +38,17 @@ fun NavGraphBuilder.homeGraph( modifier = modifier, navToProfile = remember { { username -> - viewModel.sendAction(Action.OnUserClick(username)) + store.sendAction(Action.OnUserClick(username)) } }, navToCollection = remember { { uuid -> - viewModel.sendAction(Action.OnCollectionClick(uuid)) + store.sendAction(Action.OnCollectionClick(uuid)) } }, navToImage = remember { { uuid -> - viewModel.sendAction(Action.OnImageClick(uuid)) + store.sendAction(Action.OnImageClick(uuid)) } }, collections = remember { collections }, diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouter.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouter.kt index 526bb08f..fd924253 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouter.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeRouter.kt @@ -1,6 +1,6 @@ package st.slex.csplashscreen.feature.home.navigation import st.slex.csplashscreen.core.ui.mvi.Router -import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent -interface HomeRouter : Router +interface HomeRouter : Router 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 537e8725..9c5637c1 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 @@ -2,10 +2,9 @@ package st.slex.csplashscreen.feature.home.navigation 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.HomeStore.Navigation -import javax.inject.Inject +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.Navigation -class HomeRouterImpl @Inject constructor( +class HomeRouterImpl( private val navigator: Navigator ) : HomeRouter { diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt index 4802e085..02b9d8de 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt @@ -1,68 +1,80 @@ package st.slex.csplashscreen.feature.home.ui.presenter -import androidx.compose.runtime.Stable +import androidx.paging.Pager +import androidx.paging.PagingConfig import androidx.paging.PagingData +import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.collection.ui.model.CollectionModel +import st.slex.csplashscreen.core.collection.ui.model.toPresentation +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.photos.ui.model.toPresentation import st.slex.csplashscreen.core.ui.mvi.Store +import st.slex.csplashscreen.core.ui.paging.PagingSource +import st.slex.csplashscreen.feature.home.domain.HomeInteractor +import st.slex.csplashscreen.feature.home.navigation.HomeRouter +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.Action +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.Event +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.Navigation +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStoreComponent.State -interface HomeStore : Store { +class HomeStore( + private val interactor: HomeInteractor, + appDispatcher: AppDispatcher, + router: HomeRouter +) : Store( + router = router, + appDispatcher = appDispatcher, + initialState = State.INIT +) { - @Stable - data class State( - val collections: PagingData, - val photos: PagingData - ) : Store.State { + private val collections: StateFlow> + get() = Pager(config = config) { PagingSource(interactor::getAllCollections) } + .state { collection -> collection.toPresentation() } - companion object { - val INIT = State( - collections = PagingData.empty(), - photos = PagingData.empty() - ) + private val photos: StateFlow> + get() = Pager(config = config) { PagingSource(interactor::getAllPhotos) } + .state { image -> image.toPresentation() } + + override fun sendAction(action: Action) { + when (action) { + is Action.Init -> actionInit() + is Action.OnCollectionClick -> actionCollectionClick(action) + is Action.OnImageClick -> actionImageClick(action) + is Action.OnUserClick -> actionUserClick(action) } } - @Stable - sealed interface Event : Store.Event - - @Stable - sealed interface Navigation : Store.Navigation { - - @Stable - data class User( - val username: String - ) : Navigation - - @Stable - data class Collection( - val uuid: String - ) : Navigation - - @Stable - data class Image( - val uuid: String - ) : Navigation + private fun actionInit() { + collections.launch { data -> + updateState { currentState -> + currentState.copy(collections = data) + } + } + photos.launch { data -> + updateState { currentState -> + currentState.copy(photos = data) + } + } } - @Stable - sealed interface Action : Store.Action { + private fun actionCollectionClick(action: Action.OnCollectionClick) { + navigate(Navigation.Collection(action.uuid)) + } - data object Init : Action + private fun actionImageClick(action: Action.OnImageClick) { + navigate(Navigation.Image(action.uuid)) + } - @Stable - data class OnUserClick( - val username: String - ) : Action + private fun actionUserClick(action: Action.OnUserClick) { + navigate(Navigation.User(action.username)) + } - @Stable - data class OnCollectionClick( - val uuid: String - ) : Action + companion object { - @Stable - data class OnImageClick( - val uuid: String - ) : Action + private val config = PagingConfig( + pageSize = 10, + enablePlaceholders = false + ) } -} - +} \ No newline at end of file diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStoreComponent.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStoreComponent.kt new file mode 100644 index 00000000..d23189a7 --- /dev/null +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStoreComponent.kt @@ -0,0 +1,68 @@ +package st.slex.csplashscreen.feature.home.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.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.ui.mvi.StoreComponent + +interface HomeStoreComponent : StoreComponent { + + @Stable + data class State( + val collections: PagingData, + val photos: PagingData + ) : StoreComponent.State { + + companion object { + val INIT = State( + collections = PagingData.empty(), + photos = PagingData.empty() + ) + } + } + + @Stable + sealed interface Event : StoreComponent.Event + + @Stable + sealed interface Navigation : StoreComponent.Navigation { + + @Stable + data class User( + val username: String + ) : Navigation + + @Stable + data class Collection( + val uuid: String + ) : Navigation + + @Stable + data class Image( + val uuid: String + ) : Navigation + } + + @Stable + sealed interface Action : StoreComponent.Action { + + data object Init : Action + + @Stable + data class OnUserClick( + val username: String + ) : Action + + @Stable + data class OnCollectionClick( + val uuid: String + ) : Action + + @Stable + data class OnImageClick( + val uuid: String + ) : Action + } +} + diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt deleted file mode 100644 index 481b67bf..00000000 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt +++ /dev/null @@ -1,81 +0,0 @@ -package st.slex.csplashscreen.feature.home.ui.presenter - -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingData -import kotlinx.coroutines.flow.StateFlow -import st.slex.csplashscreen.core.collection.ui.model.CollectionModel -import st.slex.csplashscreen.core.collection.ui.model.toPresentation -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.photos.ui.model.PhotoModel -import st.slex.csplashscreen.core.photos.ui.model.toPresentation -import st.slex.csplashscreen.core.ui.mvi.BaseViewModel -import st.slex.csplashscreen.core.ui.paging.PagingSource -import st.slex.csplashscreen.feature.home.domain.HomeInteractor -import st.slex.csplashscreen.feature.home.navigation.HomeRouter -import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore.Action -import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore.Event -import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore.Navigation -import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore.State -import javax.inject.Inject - -class HomeViewModel @Inject constructor( - private val interactor: HomeInteractor, - appDispatcher: AppDispatcher, - router: HomeRouter -) : BaseViewModel( - router = router, - appDispatcher = appDispatcher, - initialState = State.INIT -) { - - private val collections: StateFlow> - get() = Pager(config = config) { PagingSource(interactor::getAllCollections) } - .state { collection -> collection.toPresentation() } - - private val photos: StateFlow> - get() = Pager(config = config) { PagingSource(interactor::getAllPhotos) } - .state { image -> image.toPresentation() } - - override fun sendAction(action: Action) { - when (action) { - is Action.Init -> actionInit() - is Action.OnCollectionClick -> actionCollectionClick(action) - is Action.OnImageClick -> actionImageClick(action) - is Action.OnUserClick -> actionUserClick(action) - } - } - - private fun actionInit() { - collections.launch { data -> - updateState { currentState -> - currentState.copy(collections = data) - } - } - photos.launch { data -> - updateState { currentState -> - currentState.copy(photos = data) - } - } - } - - private fun actionCollectionClick(action: Action.OnCollectionClick) { - navigate(Navigation.Collection(action.uuid)) - } - - private fun actionImageClick(action: Action.OnImageClick) { - navigate(Navigation.Image(action.uuid)) - } - - private fun actionUserClick(action: Action.OnUserClick) { - navigate(Navigation.User(action.username)) - } - - companion object { - - private val config = PagingConfig( - pageSize = 10, - enablePlaceholders = false - ) - } -} \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponent.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponent.kt deleted file mode 100644 index 729983d5..00000000 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponent.kt +++ /dev/null @@ -1,40 +0,0 @@ -package st.slex.csplashscreen.feature.feature_photo_detail.di - -import dagger.Component -import st.slex.csplashscreen.core.favourite.di.FavouriteApi -import st.slex.csplashscreen.core.photos.di.PhotosApi -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.Feature - -@Component( - dependencies = [ImageDetailDependencies::class], - modules = [ImageDetailModule::class] -) -@ImageDetailScope -interface ImageDetailComponent : Feature { - - @Component.Factory - interface Factory { - fun create(dependencies: ImageDetailDependencies): ImageDetailComponent - } - - @Component( - dependencies = [ - MainUiApi::class, - PhotosApi::class, - FavouriteApi::class, - ] - ) - @ImageDetailScope - interface ImageDetailDependenciesComponent : ImageDetailDependencies { - - @Component.Factory - interface Factory { - fun create( - mainUiApi: MainUiApi, - photosApi: PhotosApi, - favouriteApi: FavouriteApi, - ): ImageDetailDependencies - } - } -} \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponentBuilder.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponentBuilder.kt deleted file mode 100644 index 8918f583..00000000 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailComponentBuilder.kt +++ /dev/null @@ -1,23 +0,0 @@ -package st.slex.csplashscreen.feature.feature_photo_detail.di - -import st.slex.csplashscreen.core.favourite.di.FavouriteApiBuilder -import st.slex.csplashscreen.core.photos.di.PhotosApiBuilder -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder - -object ImageDetailComponentBuilder : FeatureBuilder() { - - override val key: Any = "image-detail-feature" - - override fun create(mainUiApi: MainUiApi) = DaggerImageDetailComponent - .factory() - .create( - dependencies = DaggerImageDetailComponent_ImageDetailDependenciesComponent - .factory() - .create( - mainUiApi = mainUiApi, - photosApi = PhotosApiBuilder.build(mainUiApi), - favouriteApi = FavouriteApiBuilder.build(mainUiApi), - ) - ) -} diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailDependencies.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailDependencies.kt deleted file mode 100644 index 7f59ad86..00000000 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailDependencies.kt +++ /dev/null @@ -1,23 +0,0 @@ -package st.slex.csplashscreen.feature.feature_photo_detail.di - -import android.content.Context -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.favourite.data.repository.FavouriteRepository -import st.slex.csplashscreen.core.favourite.domain.FavouriteInteractor -import st.slex.csplashscreen.core.navigation.navigator.Navigator -import st.slex.csplashscreen.core.photos.data.PhotosRepository - -interface ImageDetailDependencies { - - val context: Context - - val navigator: Navigator - - val repository: PhotosRepository - - val favouriteRepository: FavouriteRepository - - val favouriteInteractor: FavouriteInteractor - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailModule.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailModule.kt deleted file mode 100644 index f63f995e..00000000 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailModule.kt +++ /dev/null @@ -1,47 +0,0 @@ -package st.slex.csplashscreen.feature.feature_photo_detail.di - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import st.slex.csplashscreen.core.ui.base.ViewModelFactory -import st.slex.csplashscreen.core.ui.di.ViewModelKey -import st.slex.csplashscreen.feature.feature_photo_detail.domain.interactor.ImageDetailInteractor -import st.slex.csplashscreen.feature.feature_photo_detail.domain.interactor.ImageDetailInteractorImpl -import st.slex.csplashscreen.feature.feature_photo_detail.navigation.ImageDetailRouter -import st.slex.csplashscreen.feature.feature_photo_detail.navigation.ImageDetailRouterImpl -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailViewModel -import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.DownloadImageUseCase -import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.DownloadImageUseCaseImpl -import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.WallpaperSetUseCase -import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.WallpaperSetUseCaseImpl - -@Module -interface ImageDetailModule { - - @Binds - @ImageDetailScope - fun bindsInteractor(impl: ImageDetailInteractorImpl): ImageDetailInteractor - - @Binds - @ImageDetailScope - fun bindsRouter(impl: ImageDetailRouterImpl): ImageDetailRouter - - @Binds - @ImageDetailScope - fun bindsViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory - - @Binds - @IntoMap - @ViewModelKey(ImageDetailViewModel::class) - fun bindsViewModel(impl: ImageDetailViewModel): ViewModel - - @Binds - @ImageDetailScope - fun bindsWallpaperUserCase(impl: WallpaperSetUseCaseImpl): WallpaperSetUseCase - - @Binds - @ImageDetailScope - fun bindsDownloadImageUseCase(impl: DownloadImageUseCaseImpl): DownloadImageUseCase -} \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailScope.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailScope.kt deleted file mode 100644 index fe9434e8..00000000 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ImageDetailScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package st.slex.csplashscreen.feature.feature_photo_detail.di - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class ImageDetailScope diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ModuleFeatureImageDetail.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ModuleFeatureImageDetail.kt new file mode 100644 index 00000000..5d7b98ae --- /dev/null +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/di/ModuleFeatureImageDetail.kt @@ -0,0 +1,23 @@ +package st.slex.csplashscreen.feature.feature_photo_detail.di + +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module +import st.slex.csplashscreen.feature.feature_photo_detail.domain.interactor.ImageDetailInteractor +import st.slex.csplashscreen.feature.feature_photo_detail.domain.interactor.ImageDetailInteractorImpl +import st.slex.csplashscreen.feature.feature_photo_detail.navigation.ImageDetailRouter +import st.slex.csplashscreen.feature.feature_photo_detail.navigation.ImageDetailRouterImpl +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore +import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.DownloadImageUseCase +import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.DownloadImageUseCaseImpl +import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.WallpaperSetUseCase +import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.WallpaperSetUseCaseImpl + +val moduleFeatureImageDetail = module { + factoryOf(::ImageDetailInteractorImpl) { bind() } + factoryOf(::ImageDetailRouterImpl) { bind() } + viewModelOf(::ImageDetailStore) + factoryOf(::WallpaperSetUseCaseImpl) { bind() } + factoryOf(::DownloadImageUseCaseImpl) { bind() } +} \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/domain/interactor/ImageDetailInteractorImpl.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/domain/interactor/ImageDetailInteractorImpl.kt index 6748a595..c2d314c4 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/domain/interactor/ImageDetailInteractorImpl.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/domain/interactor/ImageDetailInteractorImpl.kt @@ -10,9 +10,8 @@ import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.feature.feature_photo_detail.domain.model.ImageDetail import st.slex.csplashscreen.feature.feature_photo_detail.domain.model.ImageDetailMapper.toImageDetail import st.slex.csplashscreen.feature.feature_photo_detail.domain.model.ImageDetailMapper.transformDetail -import javax.inject.Inject -class ImageDetailInteractorImpl @Inject constructor( +class ImageDetailInteractorImpl( private val repository: PhotosRepository, private val favouriteRepository: FavouriteRepository, private val favouriteInteractor: FavouriteInteractor 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 07ee1a92..f9f41a45 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 @@ -17,30 +17,26 @@ 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.ui.utils.CollectAsEvent -import st.slex.csplashscreen.feature.feature_photo_detail.di.ImageDetailComponentBuilder import st.slex.csplashscreen.feature.feature_photo_detail.ui.ImageDetailScreen import st.slex.csplashscreen.feature.feature_photo_detail.ui.components.dialogs.DownloadImageDialog -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.Action -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.DialogType -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.Event -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailViewModel +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Action +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.DialogType +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Event fun NavGraphBuilder.imageDetailGraph( modifier: Modifier = Modifier, ) { - createScreen( - appDestination = AppDestination.IMAGE_DETAIL, - featureBuilder = ImageDetailComponentBuilder - ) { viewModel: ImageDetailViewModel, args -> + createScreen(AppDestination.IMAGE_DETAIL) { store: ImageDetailStore, args -> val arguments = args.firstOrNull() .orEmpty() .let(AppArguments::ImageDetailScreen) LaunchedEffect(arguments) { - viewModel.sendAction(Action.Init(arguments)) + store.sendAction(Action.Init(arguments)) } - val state by remember { viewModel.state }.collectAsState() + val state by remember { store.state }.collectAsState() var dialogType by remember { mutableStateOf(DialogType.NONE) @@ -52,7 +48,7 @@ fun NavGraphBuilder.imageDetailGraph( label = "anim_blur_dialog_background" ) - viewModel.event.CollectAsEvent { event -> + store.event.CollectAsEvent { event -> when (event) { is Event.Dialog -> dialogType = event.type } @@ -62,30 +58,30 @@ fun NavGraphBuilder.imageDetailGraph( modifier = modifier.blur(blurBackground), state = state, onProfileClick = remember { - { username -> viewModel.sendAction(Action.OnProfileClick(username)) } + { username -> store.sendAction(Action.OnProfileClick(username)) } }, onDownloadImageClick = remember { - { viewModel.sendAction(Action.DownloadImageButtonClick) } + { store.sendAction(Action.DownloadImageButtonClick) } }, onTagClick = remember { - { tag -> viewModel.sendAction(Action.OnTagClick(tag)) } + { tag -> store.sendAction(Action.OnTagClick(tag)) } }, onSetWallpaperClick = remember { - { url -> viewModel.sendAction(Action.SetWallpaperClick(url)) } + { url -> store.sendAction(Action.SetWallpaperClick(url)) } }, onLikeClicked = remember { - { image -> viewModel.sendAction(Action.OnLikeClicked(image)) } + { image -> store.sendAction(Action.OnLikeClicked(image)) } } ) if (dialogType != DialogType.NONE) { Dialog( onDismissRequest = { - viewModel.sendAction(Action.CloseDialog) + store.sendAction(Action.CloseDialog) }, ) { when (dialogType) { - DialogType.DOWNLOAD -> DownloadImageDialog(viewModel::sendAction) + DialogType.DOWNLOAD -> DownloadImageDialog(store::sendAction) DialogType.NONE -> Unit } } diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouter.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouter.kt index 82446872..511a2dd3 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouter.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/navigation/ImageDetailRouter.kt @@ -1,6 +1,6 @@ package st.slex.csplashscreen.feature.feature_photo_detail.navigation import st.slex.csplashscreen.core.ui.mvi.Router -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.Navigation +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Navigation interface ImageDetailRouter : Router 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 2a9edef1..24aa598d 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 @@ -2,10 +2,9 @@ package st.slex.csplashscreen.feature.feature_photo_detail.navigation import st.slex.csplashscreen.core.navigation.navigator.NavigationTarget.Screen import st.slex.csplashscreen.core.navigation.navigator.Navigator -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.Navigation -import javax.inject.Inject +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Navigation -class ImageDetailRouterImpl @Inject constructor( +class ImageDetailRouterImpl( private val navigator: Navigator ) : ImageDetailRouter { diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/ImageDetailScreen.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/ImageDetailScreen.kt index 5e0a6944..76b6d631 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/ImageDetailScreen.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/ImageDetailScreen.kt @@ -39,7 +39,7 @@ import st.slex.csplashscreen.core.ui.components.UserImageHeadWithUserName import st.slex.csplashscreen.core.ui.theme.Dimen import st.slex.csplashscreen.feature.feature_photo_detail.R import st.slex.csplashscreen.feature.feature_photo_detail.domain.model.ImageDetail -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.State +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.State import st.slex.csplashscreen.feature.feature_photo_detail.ui.components.DetailImageBodyTags @Composable diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/components/dialogs/DownloadImageDialog.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/components/dialogs/DownloadImageDialog.kt index 0a49cb0a..e0dd5479 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/components/dialogs/DownloadImageDialog.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/components/dialogs/DownloadImageDialog.kt @@ -20,11 +20,11 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.text.style.TextAlign import st.slex.csplashscreen.core.ui.theme.Dimen import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent @Composable fun DownloadImageDialog( - onAction: (ImageDetailStore.Action.DownloadImageChooseClick) -> Unit, + onAction: (ImageDetailStoreComponent.Action.DownloadImageChooseClick) -> Unit, modifier: Modifier = Modifier, ) { Box( @@ -45,7 +45,7 @@ fun DownloadImageDialog( Button( modifier = Modifier.fillMaxWidth(), onClick = { - onAction(ImageDetailStore.Action.DownloadImageChooseClick(type)) + onAction(ImageDetailStoreComponent.Action.DownloadImageChooseClick(type)) }, ) { Text( 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 1b8c4243..1927693a 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 @@ -1,111 +1,121 @@ 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.core.Logger +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher import st.slex.csplashscreen.core.ui.mvi.Store -import st.slex.csplashscreen.feature.feature_photo_detail.domain.model.ImageDetail +import st.slex.csplashscreen.feature.feature_photo_detail.domain.interactor.ImageDetailInteractor +import st.slex.csplashscreen.feature.feature_photo_detail.navigation.ImageDetailRouter +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.LARGE +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.MEDIUM +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.ORIGINAL +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.SMALL +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Action +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.DialogType +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Event +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.Navigation +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.ScreenState +import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStoreComponent.State +import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.DownloadImageUseCase +import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.WallpaperSetUseCase + +class ImageDetailStore( + private val interactor: ImageDetailInteractor, + private val downloadImageUseCase: DownloadImageUseCase, + private val wallpaperSetUseCase: WallpaperSetUseCase, + appDispatcher: AppDispatcher, + router: ImageDetailRouter +) : Store( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { + + override fun sendAction(action: Action) { + when (action) { + is Action.Init -> actionInit(action) + is Action.DownloadImageButtonClick -> actionDownloadImageButtonClick() + is Action.OnLikeClicked -> actionLikeClick(action) + is Action.OnProfileClick -> actionProfileClick(action) + is Action.OnTagClick -> actionTagClick(action) + is Action.SetWallpaperClick -> setWallpaperClick(action) + is Action.DownloadImageChooseClick -> actionDownloadImageChooseClick(action) + is Action.CloseDialog -> actionCloseDialog() + } + } -interface ImageDetailStore : Store { + private fun actionCloseDialog() { + sendEvent(Event.Dialog(DialogType.NONE)) + } - @Stable - data class State( - val imageId: String, - val screenState: ScreenState - ) : Store.State { + private fun actionDownloadImageButtonClick() { + // TODO Show dialog to choose type + sendEvent(Event.Dialog(DialogType.DOWNLOAD)) + } - companion object { - val INITIAL: State = State( - imageId = "", - screenState = ScreenState.Loading + private fun actionDownloadImageChooseClick( + action: Action.DownloadImageChooseClick + ) { + val photo = state.value.screenState.data?.photo ?: return // TODO show Toast + launchCatching( + block = { + when (action.type) { + LARGE -> photo.urls.raw + MEDIUM -> photo.urls.regular + SMALL -> photo.urls.small + ORIGINAL -> interactor.getDownloadLink(state.value.imageId) + } + } + ) { downloadUrl -> + downloadImageUseCase( + url = downloadUrl, + fileName = state.value.imageId ) + sendEvent(Event.Dialog(DialogType.NONE)) } } - @Stable - sealed interface ScreenState { - - @Stable - data object Loading : ScreenState - - @Stable - data class Content( - val imageDetail: ImageDetail - ) : ScreenState - - @Stable - data class Error( - val throwable: Throwable - ) : ScreenState - - val data: ImageDetail? - get() = (this as? Content)?.imageDetail + private fun actionLikeClick(action: Action.OnLikeClicked) { + launch { + runCatching { + interactor.like(action.imageDetail.photo) + }.onFailure { error -> + Logger.exception(error) + } + } } - @Stable - sealed interface Event : Store.Event { - - @Stable - data class Dialog( - val type: DialogType - ) : Event + private fun actionProfileClick(action: Action.OnProfileClick) { + navigate(Navigation.Profile(action.username)) } - enum class DialogType { - DOWNLOAD, - NONE + private fun actionTagClick(action: Action.OnTagClick) { + navigate(Navigation.Search(action.tag)) } - @Stable - sealed interface Navigation : Store.Navigation { - - @Stable - data class Profile( - val username: String - ) : Navigation - - @Stable - data class Search( - val tag: String - ) : Navigation + private fun setWallpaperClick(action: Action.SetWallpaperClick) { + wallpaperSetUseCase(action.url) } - @Stable - sealed interface Action : Store.Action { - - @Stable - data class Init( - val args: AppArguments.ImageDetailScreen - ) : Action - - @Stable - data class SetWallpaperClick( - val url: String - ) : Action - - @Stable - data class OnTagClick( - val tag: String - ) : Action - - @Stable - data class OnProfileClick( - val username: String - ) : Action - - @Stable - data class OnLikeClicked( - val imageDetail: ImageDetail - ) : Action - - @Stable - data object DownloadImageButtonClick : Action - - @Stable - data class DownloadImageChooseClick( - val type: DownloadImageType - ) : Action - - @Stable - data object CloseDialog : Action + private fun actionInit(action: Action.Init) { + updateState { currentState -> + currentState.copy(imageId = action.args.imageId) + } + interactor.getImageDetail(action.args.imageId) + .launch( + onError = { error -> + updateState { currentState -> + currentState.copy( + screenState = ScreenState.Error(error) + ) + } + }, + each = { imageDetail -> + updateState { currentState -> + currentState.copy( + screenState = ScreenState.Content(imageDetail) + ) + } + } + ) } -} +} \ No newline at end of file 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 new file mode 100644 index 00000000..4fa12818 --- /dev/null +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStoreComponent.kt @@ -0,0 +1,111 @@ +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.ui.mvi.StoreComponent +import st.slex.csplashscreen.feature.feature_photo_detail.domain.model.ImageDetail + +interface ImageDetailStoreComponent : StoreComponent { + + @Stable + data class State( + val imageId: String, + val screenState: ScreenState + ) : StoreComponent.State { + + companion object { + val INITIAL: State = State( + imageId = "", + screenState = ScreenState.Loading + ) + } + } + + @Stable + sealed interface ScreenState { + + @Stable + data object Loading : ScreenState + + @Stable + data class Content( + val imageDetail: ImageDetail + ) : ScreenState + + @Stable + data class Error( + val throwable: Throwable + ) : ScreenState + + val data: ImageDetail? + get() = (this as? Content)?.imageDetail + } + + @Stable + sealed interface Event : StoreComponent.Event { + + @Stable + data class Dialog( + val type: DialogType + ) : Event + } + + enum class DialogType { + DOWNLOAD, + NONE + } + + @Stable + sealed interface Navigation : StoreComponent.Navigation { + + @Stable + data class Profile( + val username: String + ) : Navigation + + @Stable + data class Search( + val tag: String + ) : Navigation + } + + @Stable + sealed interface Action : StoreComponent.Action { + + @Stable + data class Init( + val args: AppArguments.ImageDetailScreen + ) : Action + + @Stable + data class SetWallpaperClick( + val url: String + ) : Action + + @Stable + data class OnTagClick( + val tag: String + ) : Action + + @Stable + data class OnProfileClick( + val username: String + ) : Action + + @Stable + data class OnLikeClicked( + val imageDetail: ImageDetail + ) : Action + + @Stable + data object DownloadImageButtonClick : Action + + @Stable + data class DownloadImageChooseClick( + val type: DownloadImageType + ) : Action + + @Stable + data object CloseDialog : Action + } +} diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt deleted file mode 100644 index 1174a480..00000000 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt +++ /dev/null @@ -1,122 +0,0 @@ -package st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter - -import st.slex.csplashscreen.core.core.Logger -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.ui.mvi.BaseViewModel -import st.slex.csplashscreen.feature.feature_photo_detail.domain.interactor.ImageDetailInteractor -import st.slex.csplashscreen.feature.feature_photo_detail.navigation.ImageDetailRouter -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.LARGE -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.MEDIUM -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.ORIGINAL -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.DownloadImageType.SMALL -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.Action -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.DialogType -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.Event -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.Navigation -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.ScreenState -import st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter.ImageDetailStore.State -import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.DownloadImageUseCase -import st.slex.csplashscreen.feature.feature_photo_detail.ui.utils.WallpaperSetUseCase -import javax.inject.Inject - -class ImageDetailViewModel @Inject constructor( - private val interactor: ImageDetailInteractor, - private val downloadImageUseCase: DownloadImageUseCase, - private val wallpaperSetUseCase: WallpaperSetUseCase, - appDispatcher: AppDispatcher, - router: ImageDetailRouter -) : BaseViewModel( - router = router, - appDispatcher = appDispatcher, - initialState = State.INITIAL -) { - - override fun sendAction(action: Action) { - when (action) { - is Action.Init -> actionInit(action) - is Action.DownloadImageButtonClick -> actionDownloadImageButtonClick() - is Action.OnLikeClicked -> actionLikeClick(action) - is Action.OnProfileClick -> actionProfileClick(action) - is Action.OnTagClick -> actionTagClick(action) - is Action.SetWallpaperClick -> setWallpaperClick(action) - is Action.DownloadImageChooseClick -> actionDownloadImageChooseClick(action) - is Action.CloseDialog -> actionCloseDialog() - } - } - - private fun actionCloseDialog() { - sendEvent(Event.Dialog(DialogType.NONE)) - } - - private fun actionDownloadImageButtonClick() { - // TODO Show dialog to choose type - sendEvent(Event.Dialog(DialogType.DOWNLOAD)) - } - - private fun actionDownloadImageChooseClick( - action: Action.DownloadImageChooseClick - ) { - val photo = state.value.screenState.data?.photo ?: return // TODO show Toast - launchCatching( - block = { - when (action.type) { - LARGE -> photo.urls.raw - MEDIUM -> photo.urls.regular - SMALL -> photo.urls.small - ORIGINAL -> interactor.getDownloadLink(state.value.imageId) - } - } - ) { downloadUrl -> - downloadImageUseCase( - url = downloadUrl, - fileName = state.value.imageId - ) - sendEvent(Event.Dialog(DialogType.NONE)) - } - } - - private fun actionLikeClick(action: Action.OnLikeClicked) { - launch { - runCatching { - interactor.like(action.imageDetail.photo) - }.onFailure { error -> - Logger.exception(error) - } - } - } - - private fun actionProfileClick(action: Action.OnProfileClick) { - navigate(Navigation.Profile(action.username)) - } - - private fun actionTagClick(action: Action.OnTagClick) { - navigate(Navigation.Search(action.tag)) - } - - private fun setWallpaperClick(action: Action.SetWallpaperClick) { - wallpaperSetUseCase(action.url) - } - - private fun actionInit(action: Action.Init) { - updateState { currentState -> - currentState.copy(imageId = action.args.imageId) - } - interactor.getImageDetail(action.args.imageId) - .launch( - onError = { error -> - updateState { currentState -> - currentState.copy( - screenState = ScreenState.Error(error) - ) - } - }, - each = { imageDetail -> - updateState { currentState -> - currentState.copy( - screenState = ScreenState.Content(imageDetail) - ) - } - } - ) - } -} \ No newline at end of file diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/DownloadImageUseCaseImpl.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/DownloadImageUseCaseImpl.kt index d17af379..d59f61b1 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/DownloadImageUseCaseImpl.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/DownloadImageUseCaseImpl.kt @@ -5,9 +5,8 @@ import android.content.Context import android.net.Uri import android.os.Environment import st.slex.csplashscreen.feature.feature_photo_detail.R -import javax.inject.Inject -class DownloadImageUseCaseImpl @Inject constructor( +class DownloadImageUseCaseImpl( private val context: Context ) : DownloadImageUseCase { diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/WallpaperSetUseCaseImpl.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/WallpaperSetUseCaseImpl.kt index 7a455828..ad1caf38 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/WallpaperSetUseCaseImpl.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/utils/WallpaperSetUseCaseImpl.kt @@ -6,9 +6,8 @@ import androidx.core.graphics.drawable.toBitmap import coil.ImageLoader import coil.request.CachePolicy import coil.request.ImageRequest -import javax.inject.Inject -class WallpaperSetUseCaseImpl @Inject constructor( +class WallpaperSetUseCaseImpl( private val context: Context, ) : WallpaperSetUseCase { diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/data/SearchRepositoryImpl.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/data/SearchRepositoryImpl.kt index 6bbe0e33..724788fa 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/data/SearchRepositoryImpl.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/data/SearchRepositoryImpl.kt @@ -11,9 +11,8 @@ import st.slex.csplashscreen.core.database.search.SearchDao import st.slex.csplashscreen.core.database.search.SearchEntity import st.slex.csplashscreen.core.network.model.remote.image.RemoteImageModel import st.slex.csplashscreen.core.network.source.interf.SearchPhotosNetworkSource -import javax.inject.Inject -class SearchRepositoryImpl @Inject constructor( +class SearchRepositoryImpl( private val networkSource: SearchPhotosNetworkSource, private val dao: SearchDao ) : SearchRepository { diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/ModuleFeatureSearchPhotos.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/ModuleFeatureSearchPhotos.kt new file mode 100644 index 00000000..9646983c --- /dev/null +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/ModuleFeatureSearchPhotos.kt @@ -0,0 +1,21 @@ +package st.slex.csplashscreen.feature.search.di + +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module +import st.slex.csplashscreen.feature.search.data.SearchRepository +import st.slex.csplashscreen.feature.search.data.SearchRepositoryImpl +import st.slex.csplashscreen.feature.search.domain.interactor.SearchPhotosInteractor +import st.slex.csplashscreen.feature.search.domain.interactor.SearchPhotosInteractorImpl +import st.slex.csplashscreen.feature.search.navigation.SearchPhotosRouter +import st.slex.csplashscreen.feature.search.navigation.SearchPhotosRouterImpl +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore + +val moduleFeatureSearchPhotos = module { + factoryOf(::SearchRepositoryImpl) { bind() } + factoryOf(::SearchPhotosInteractorImpl) { bind() } + factoryOf(::SearchPhotosRouterImpl) { bind() } + viewModelOf(::SearchStore) +} + diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponent.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponent.kt deleted file mode 100644 index 9258d396..00000000 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponent.kt +++ /dev/null @@ -1,17 +0,0 @@ -package st.slex.csplashscreen.feature.search.di - -import dagger.Component -import st.slex.csplashscreen.core.ui.di.builder.Feature - -@Component( - dependencies = [SearchPhotosDependencies::class], - modules = [SearchPhotosModule::class] -) -@SearchPhotosScope -interface SearchPhotosComponent : Feature { - - @Component.Factory - interface Factory { - fun create(dependencies: SearchPhotosDependencies): SearchPhotosComponent - } -} diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponentBuilder.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponentBuilder.kt deleted file mode 100644 index 2d0e0f67..00000000 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosComponentBuilder.kt +++ /dev/null @@ -1,25 +0,0 @@ -package st.slex.csplashscreen.feature.search.di - -import st.slex.csplashscreen.core.database.di.DatabaseApiBuilder -import st.slex.csplashscreen.core.network.di.NetworkApiBuilder -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder - -object SearchPhotosComponentBuilder : FeatureBuilder() { - - override val key: Any = "search-photos-feature" - - override fun create( - mainUiApi: MainUiApi - ) = DaggerSearchPhotosComponent - .factory() - .create( - dependencies = DaggerSearchPhotosDependenciesComponent - .factory() - .create( - mainUiApi = mainUiApi, - databaseApi = DatabaseApiBuilder.build(mainUiApi), - networkClientApi = NetworkApiBuilder.build(mainUiApi) - ) - ) -} diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependencies.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependencies.kt deleted file mode 100644 index 8f993294..00000000 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependencies.kt +++ /dev/null @@ -1,17 +0,0 @@ -package st.slex.csplashscreen.feature.search.di - -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.database.search.SearchDao -import st.slex.csplashscreen.core.navigation.navigator.Navigator -import st.slex.csplashscreen.core.network.source.interf.SearchPhotosNetworkSource - -interface SearchPhotosDependencies { - - val searchDao: SearchDao - - val navigator: Navigator - - val networkSource: SearchPhotosNetworkSource - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependenciesComponent.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependenciesComponent.kt deleted file mode 100644 index 0d1df478..00000000 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosDependenciesComponent.kt +++ /dev/null @@ -1,26 +0,0 @@ -package st.slex.csplashscreen.feature.search.di - -import dagger.Component -import st.slex.csplashscreen.core.database.di.DatabaseApi -import st.slex.csplashscreen.core.network.di.NetworkClientApi -import st.slex.csplashscreen.core.ui.di.MainUiApi - -@Component( - dependencies = [ - MainUiApi::class, - DatabaseApi::class, - NetworkClientApi::class - ] -) -@SearchPhotosScope -interface SearchPhotosDependenciesComponent : SearchPhotosDependencies { - - @Component.Factory - interface Factory { - fun create( - mainUiApi: MainUiApi, - databaseApi: DatabaseApi, - networkClientApi: NetworkClientApi - ): SearchPhotosDependencies - } -} \ No newline at end of file diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosModule.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosModule.kt deleted file mode 100644 index b64f3538..00000000 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosModule.kt +++ /dev/null @@ -1,42 +0,0 @@ -package st.slex.csplashscreen.feature.search.di - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import st.slex.csplashscreen.core.ui.base.ViewModelFactory -import st.slex.csplashscreen.core.ui.di.ViewModelKey -import st.slex.csplashscreen.feature.search.data.SearchRepository -import st.slex.csplashscreen.feature.search.data.SearchRepositoryImpl -import st.slex.csplashscreen.feature.search.domain.interactor.SearchPhotosInteractor -import st.slex.csplashscreen.feature.search.domain.interactor.SearchPhotosInteractorImpl -import st.slex.csplashscreen.feature.search.navigation.SearchPhotosRouter -import st.slex.csplashscreen.feature.search.navigation.SearchPhotosRouterImpl -import st.slex.csplashscreen.feature.search.ui.presenter.SearchViewModel - -@Module -interface SearchPhotosModule { - - @Binds - @SearchPhotosScope - fun bindsRepository(impl: SearchRepositoryImpl): SearchRepository - - @Binds - @SearchPhotosScope - fun bindsInteractor(impl: SearchPhotosInteractorImpl): SearchPhotosInteractor - - @Binds - @SearchPhotosScope - fun bindsRouter(impl: SearchPhotosRouterImpl): SearchPhotosRouter - - @Binds - @SearchPhotosScope - fun bindsViewModelFactory(impl: ViewModelFactory): ViewModelProvider.Factory - - @Binds - @IntoMap - @ViewModelKey(SearchViewModel::class) - fun bindsViewModel(impl: SearchViewModel): ViewModel -} - diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosScope.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosScope.kt deleted file mode 100644 index 75aaa6d5..00000000 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/di/SearchPhotosScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package st.slex.csplashscreen.feature.search.di - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class SearchPhotosScope diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/domain/interactor/SearchPhotosInteractorImpl.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/domain/interactor/SearchPhotosInteractorImpl.kt index a918aa94..2f0470fd 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/domain/interactor/SearchPhotosInteractorImpl.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/domain/interactor/SearchPhotosInteractorImpl.kt @@ -15,9 +15,8 @@ import st.slex.csplashscreen.core.network.model.ui.ImageModel import st.slex.csplashscreen.feature.search.data.SearchRepository import st.slex.csplashscreen.feature.search.domain.model.SearchMapper.toPresentation import st.slex.csplashscreen.feature.search.ui.model.SearchItem -import javax.inject.Inject -class SearchPhotosInteractorImpl @Inject constructor( +class SearchPhotosInteractorImpl( private val repository: SearchRepository ) : SearchPhotosInteractor { 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 2bfaac5a..695d2ff0 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 @@ -12,33 +12,29 @@ 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.ui.utils.CollectAsEvent -import st.slex.csplashscreen.feature.search.di.SearchPhotosComponentBuilder import st.slex.csplashscreen.feature.search.ui.SearchPhotosScreen -import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore.Action -import st.slex.csplashscreen.feature.search.ui.presenter.SearchViewModel +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Action fun NavGraphBuilder.searchPhotosGraph( modifier: Modifier = Modifier, ) { - createScreen( - appDestination = AppDestination.SEARCH_PHOTOS, - featureBuilder = SearchPhotosComponentBuilder - ) { viewModel: SearchViewModel, args -> + createScreen(AppDestination.SEARCH_PHOTOS) { store: SearchStore, args -> val arguments = args.firstOrNull().orEmpty().let(AppArguments::SearchPhotosScreen) - val state by remember { viewModel.state }.collectAsState() + val state by remember { store.state }.collectAsState() val photos = remember { - viewModel.state.mapState { it.searchItems } + store.state.mapState { it.searchItems } }.collectAsLazyPagingItems() val searchHistory = remember { - viewModel.state.mapState { it.historyItems } + store.state.mapState { it.historyItems } }.collectAsLazyPagingItems() LaunchedEffect(arguments) { - viewModel.sendAction(Action.Init(arguments)) + store.sendAction(Action.Init(arguments)) } - viewModel.event.CollectAsEvent { event -> + store.event.CollectAsEvent { event -> // TODO NOT IMPLEMENTED YET } @@ -48,17 +44,17 @@ fun NavGraphBuilder.searchPhotosGraph( searchHistory = searchHistory, query = state.query, onQueryChange = remember { - { value -> viewModel.sendAction(Action.OnQueryInput(value)) } + { value -> store.sendAction(Action.OnQueryInput(value)) } }, onUserClick = remember { - { value -> viewModel.sendAction(Action.OnProfileClick(value)) } + { value -> store.sendAction(Action.OnProfileClick(value)) } }, onImageClick = remember { - { value -> viewModel.sendAction(Action.OnImageClick(value)) } + { value -> store.sendAction(Action.OnImageClick(value)) } }, - clearHistory = remember { { viewModel.sendAction(Action.ClearHistory) } }, + clearHistory = remember { { store.sendAction(Action.ClearHistory) } }, onSearchHistoryClick = remember { - { value -> viewModel.sendAction(Action.OnSearchHistoryClick(value)) } + { value -> store.sendAction(Action.OnSearchHistoryClick(value)) } } ) } diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouter.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouter.kt index 42c98348..ac5f5f26 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouter.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosRouter.kt @@ -1,6 +1,6 @@ package st.slex.csplashscreen.feature.search.navigation import st.slex.csplashscreen.core.ui.mvi.Router -import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore.Navigation +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Navigation interface SearchPhotosRouter : Router 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 9680f84b..ee99eec7 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 @@ -2,10 +2,9 @@ package st.slex.csplashscreen.feature.search.navigation 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.SearchStore.Navigation -import javax.inject.Inject +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Navigation -class SearchPhotosRouterImpl @Inject constructor( +class SearchPhotosRouterImpl( private val navigator: Navigator ) : SearchPhotosRouter { 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 87ecb926..47c9ce11 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 @@ -1,75 +1,124 @@ package st.slex.csplashscreen.feature.search.ui.presenter -import androidx.compose.runtime.Stable +import androidx.paging.Pager +import androidx.paging.PagingConfig import androidx.paging.PagingData -import st.slex.csplashscreen.core.navigation.AppArguments +import androidx.paging.map +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import st.slex.csplashscreen.core.core.Logger +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher +import st.slex.csplashscreen.core.network.model.ui.ImageModel import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.photos.ui.model.toPresentation import st.slex.csplashscreen.core.ui.mvi.Store +import st.slex.csplashscreen.core.ui.paging.PagingSource +import st.slex.csplashscreen.feature.search.domain.interactor.SearchPhotosInteractor +import st.slex.csplashscreen.feature.search.navigation.SearchPhotosRouter import st.slex.csplashscreen.feature.search.ui.model.SearchItem +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Action +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Event +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.Navigation +import st.slex.csplashscreen.feature.search.ui.presenter.SearchStoreComponent.State -interface SearchStore { +class SearchStore( + private val interactor: SearchPhotosInteractor, + appDispatcher: AppDispatcher, + router: SearchPhotosRouter +) : Store( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { - @Stable - data class State( - val query: String, - val historyItems: PagingData, - val searchItems: PagingData - ) : Store.State { - companion object { - val INITIAL = State( - query = "", - historyItems = PagingData.empty(), - searchItems = PagingData.empty() - ) - } - } - - @Stable - sealed interface Event : Store.Event + private val searchHistory: StateFlow> + get() = interactor.searchHistory.state() - @Stable - sealed interface Navigation : Store.Navigation { + @OptIn(ExperimentalCoroutinesApi::class) + private val photosSearch: StateFlow> + get() = state.map { it.query } + .distinctUntilChanged() + .map(::newPagerPhotosSearch) + .flatMapLatest { it.flow } + .map { pagingData -> pagingData.map { it.toPresentation() } } + .state() - @Stable - data class Profile( - val username: String - ) : Navigation + override fun sendAction(action: Action) { + when (action) { + is Action.Init -> actionInit(action) + is Action.ClearHistory -> actionClearHistory() + is Action.OnImageClick -> actionOnImageClick(action) + is Action.OnProfileClick -> actionOnProfileClick(action) + is Action.OnQueryInput -> actionQueryInput(action) + is Action.OnSearchHistoryClick -> actionSearchHistoryClick(action) + } + } - @Stable - data class ImageDetail( - val uuid: String - ) : Navigation + private fun actionInit(action: Action.Init) { + updateState { currentState -> + currentState.copy(query = action.args.checkedQuery) + } + searchHistory.launch { data -> + updateState { currentState -> + currentState.copy(historyItems = data) + } + } + photosSearch.launch { data -> + updateState { currentState -> + currentState.copy(searchItems = data) + } + } } - @Stable - sealed interface Action : Store.Action { + private fun newPagerPhotosSearch( + query: String + ): Pager = Pager(config) { + PagingSource { page, pageSize -> + if (query.isBlank()) { + emptyList() + } else { + interactor.getPhotos(query, page, pageSize) + } + } + } - @Stable - data class Init( - val args: AppArguments.SearchPhotosScreen - ) : Action + private fun actionSearchHistoryClick(action: Action.OnSearchHistoryClick) { + updateState { currentState -> + currentState.copy(query = action.query) + } + } - @Stable - data object ClearHistory : Action + private fun actionQueryInput(action: Action.OnQueryInput) { + updateState { currentState -> + currentState.copy(query = action.query) + } + } - @Stable - data class OnImageClick( - val uuid: String - ) : Action + private fun actionOnProfileClick(action: Action.OnProfileClick) { + navigate(Navigation.Profile(action.username)) + } - @Stable - data class OnProfileClick( - val username: String - ) : Action + private fun actionOnImageClick(action: Action.OnImageClick) { + navigate(Navigation.ImageDetail(action.uuid)) + } - @Stable - data class OnQueryInput( - val query: String - ) : Action + private fun actionClearHistory() { + launch { + runCatching { + interactor.clearHistory() + }.onFailure { error -> + Logger.exception(error) + } + } + } - @Stable - data class OnSearchHistoryClick( - val query: String - ) : Action + companion object { + private val config = PagingConfig( + pageSize = 3, + enablePlaceholders = false + ) } -} +} \ No newline at end of file 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 new file mode 100644 index 00000000..5d66d8d8 --- /dev/null +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStoreComponent.kt @@ -0,0 +1,75 @@ +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.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.ui.mvi.StoreComponent +import st.slex.csplashscreen.feature.search.ui.model.SearchItem + +interface SearchStoreComponent { + + @Stable + data class State( + val query: String, + val historyItems: PagingData, + val searchItems: PagingData + ) : StoreComponent.State { + companion object { + val INITIAL = State( + query = "", + historyItems = PagingData.empty(), + searchItems = PagingData.empty() + ) + } + } + + @Stable + sealed interface Event : StoreComponent.Event + + @Stable + sealed interface Navigation : StoreComponent.Navigation { + + @Stable + data class Profile( + val username: String + ) : Navigation + + @Stable + data class ImageDetail( + val uuid: String + ) : Navigation + } + + @Stable + sealed interface Action : StoreComponent.Action { + + @Stable + data class Init( + val args: AppArguments.SearchPhotosScreen + ) : Action + + @Stable + data object ClearHistory : Action + + @Stable + data class OnImageClick( + val uuid: String + ) : Action + + @Stable + data class OnProfileClick( + val username: String + ) : Action + + @Stable + data class OnQueryInput( + val query: String + ) : Action + + @Stable + data class OnSearchHistoryClick( + val query: String + ) : Action + } +} diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt deleted file mode 100644 index 4334f4c1..00000000 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt +++ /dev/null @@ -1,126 +0,0 @@ -package st.slex.csplashscreen.feature.search.ui.presenter - -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingData -import androidx.paging.map -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.map -import st.slex.csplashscreen.core.core.Logger -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.network.model.ui.ImageModel -import st.slex.csplashscreen.core.photos.ui.model.PhotoModel -import st.slex.csplashscreen.core.photos.ui.model.toPresentation -import st.slex.csplashscreen.core.ui.mvi.BaseViewModel -import st.slex.csplashscreen.core.ui.paging.PagingSource -import st.slex.csplashscreen.feature.search.domain.interactor.SearchPhotosInteractor -import st.slex.csplashscreen.feature.search.navigation.SearchPhotosRouter -import st.slex.csplashscreen.feature.search.ui.model.SearchItem -import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore.Action -import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore.Event -import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore.Navigation -import st.slex.csplashscreen.feature.search.ui.presenter.SearchStore.State -import javax.inject.Inject - -class SearchViewModel @Inject constructor( - private val interactor: SearchPhotosInteractor, - appDispatcher: AppDispatcher, - router: SearchPhotosRouter -) : BaseViewModel( - router = router, - appDispatcher = appDispatcher, - initialState = State.INITIAL -) { - - private val searchHistory: StateFlow> - get() = interactor.searchHistory.state() - - @OptIn(ExperimentalCoroutinesApi::class) - private val photosSearch: StateFlow> - get() = state.map { it.query } - .distinctUntilChanged() - .map(::newPagerPhotosSearch) - .flatMapLatest { it.flow } - .map { pagingData -> pagingData.map { it.toPresentation() } } - .state() - - override fun sendAction(action: Action) { - when (action) { - is Action.Init -> actionInit(action) - is Action.ClearHistory -> actionClearHistory() - is Action.OnImageClick -> actionOnImageClick(action) - is Action.OnProfileClick -> actionOnProfileClick(action) - is Action.OnQueryInput -> actionQueryInput(action) - is Action.OnSearchHistoryClick -> actionSearchHistoryClick(action) - } - } - - private fun actionInit(action: Action.Init) { - updateState { currentState -> - currentState.copy(query = action.args.checkedQuery) - } - searchHistory.launch { data -> - updateState { currentState -> - currentState.copy(historyItems = data) - } - } - photosSearch.launch { data -> - updateState { currentState -> - currentState.copy(searchItems = data) - } - } - } - - private fun newPagerPhotosSearch( - query: String - ): Pager = Pager(config) { - PagingSource { page, pageSize -> - if (query.isBlank()) { - emptyList() - } else { - interactor.getPhotos(query, page, pageSize) - } - } - } - - private fun actionSearchHistoryClick(action: Action.OnSearchHistoryClick) { - updateState { currentState -> - currentState.copy(query = action.query) - } - } - - private fun actionQueryInput(action: Action.OnQueryInput) { - updateState { currentState -> - currentState.copy(query = action.query) - } - } - - private fun actionOnProfileClick(action: Action.OnProfileClick) { - navigate(Navigation.Profile(action.username)) - } - - private fun actionOnImageClick(action: Action.OnImageClick) { - navigate(Navigation.ImageDetail(action.uuid)) - } - - private fun actionClearHistory() { - launch { - runCatching { - interactor.clearHistory() - }.onFailure { error -> - Logger.exception(error) - } - } - } - - companion object { - private val config = PagingConfig( - pageSize = 3, - enablePlaceholders = false - ) - } -} \ No newline at end of file diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/data/UserRepositoryImpl.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/data/UserRepositoryImpl.kt index 1214d414..7470c624 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/data/UserRepositoryImpl.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/data/UserRepositoryImpl.kt @@ -6,9 +6,8 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import st.slex.csplashscreen.core.network.model.remote.user.RemoteUserModel import st.slex.csplashscreen.core.network.source.interf.UserNetworkSource -import javax.inject.Inject -class UserRepositoryImpl @Inject constructor( +class UserRepositoryImpl( private val userSource: UserNetworkSource ) : UserRepository { diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/ModuleFeatureUser.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/ModuleFeatureUser.kt new file mode 100644 index 00000000..f9b100de --- /dev/null +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/ModuleFeatureUser.kt @@ -0,0 +1,20 @@ +package st.slex.csplashscreen.feature.user.di + +import org.koin.androidx.viewmodel.dsl.viewModelOf +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.factoryOf +import org.koin.dsl.module +import st.slex.csplashscreen.feature.user.data.UserRepository +import st.slex.csplashscreen.feature.user.data.UserRepositoryImpl +import st.slex.csplashscreen.feature.user.domain.UserInteractor +import st.slex.csplashscreen.feature.user.domain.UserInteractorImpl +import st.slex.csplashscreen.feature.user.navigation.UserRouter +import st.slex.csplashscreen.feature.user.navigation.UserRouterImpl +import st.slex.csplashscreen.feature.user.ui.presenter.UserStore + +val moduleFeatureUser = module { + factoryOf(::UserRepositoryImpl) { bind() } + factoryOf(::UserInteractorImpl) { bind() } + factoryOf(::UserRouterImpl) { bind() } + viewModelOf(::UserStore) +} \ No newline at end of file diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponent.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponent.kt deleted file mode 100644 index b5a97f16..00000000 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponent.kt +++ /dev/null @@ -1,42 +0,0 @@ -package st.slex.csplashscreen.feature.user.di - -import dagger.Component -import st.slex.csplashscreen.core.collection.di.CollectionApi -import st.slex.csplashscreen.core.network.di.NetworkClientApi -import st.slex.csplashscreen.core.photos.di.PhotosApi -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.Feature - -@Component( - dependencies = [UserDependencies::class], - modules = [UserModule::class] -) -@UserScope -interface UserComponent : Feature { - - @Component.Factory - interface Factory { - fun create(dependencies: UserDependencies): UserComponent - } - - @Component( - dependencies = [ - MainUiApi::class, - NetworkClientApi::class, - PhotosApi::class, - CollectionApi::class - ] - ) - interface UserDependenciesComponent : UserDependencies { - - @Component.Factory - interface Factory { - fun create( - mainUiApi: MainUiApi, - networkClientApi: NetworkClientApi, - photosApi: PhotosApi, - collectionApi: CollectionApi - ): UserDependencies - } - } -} \ No newline at end of file diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponentBuilder.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponentBuilder.kt deleted file mode 100644 index f9c42cc6..00000000 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserComponentBuilder.kt +++ /dev/null @@ -1,25 +0,0 @@ -package st.slex.csplashscreen.feature.user.di - -import st.slex.csplashscreen.core.collection.di.CollectionApiBuilder -import st.slex.csplashscreen.core.network.di.NetworkApiBuilder -import st.slex.csplashscreen.core.photos.di.PhotosApiBuilder -import st.slex.csplashscreen.core.ui.di.MainUiApi -import st.slex.csplashscreen.core.ui.di.builder.FeatureBuilder - -object UserComponentBuilder : FeatureBuilder() { - - override val key: Any = "user-feature" - - override fun create(mainUiApi: MainUiApi) = DaggerUserComponent - .factory() - .create( - dependencies = DaggerUserComponent_UserDependenciesComponent - .factory() - .create( - mainUiApi = mainUiApi, - networkClientApi = NetworkApiBuilder.build(mainUiApi), - photosApi = PhotosApiBuilder.build(mainUiApi), - collectionApi = CollectionApiBuilder.build(mainUiApi) - ) - ) -} diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserDependencies.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserDependencies.kt deleted file mode 100644 index 74d34a15..00000000 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserDependencies.kt +++ /dev/null @@ -1,20 +0,0 @@ -package st.slex.csplashscreen.feature.user.di - -import st.slex.csplashscreen.core.collection.data.CollectionsRepository -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.navigation.navigator.Navigator -import st.slex.csplashscreen.core.network.source.interf.UserNetworkSource -import st.slex.csplashscreen.core.photos.data.PhotosRepository - -interface UserDependencies { - - val userSource: UserNetworkSource - - val navigator: Navigator - - val photosRepository: PhotosRepository - - val collectionsRepository: CollectionsRepository - - val appDispatcher: AppDispatcher -} \ No newline at end of file diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserModule.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserModule.kt deleted file mode 100644 index ee918423..00000000 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserModule.kt +++ /dev/null @@ -1,41 +0,0 @@ -package st.slex.csplashscreen.feature.user.di - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import st.slex.csplashscreen.core.ui.base.ViewModelFactory -import st.slex.csplashscreen.core.ui.di.ViewModelKey -import st.slex.csplashscreen.feature.user.data.UserRepository -import st.slex.csplashscreen.feature.user.data.UserRepositoryImpl -import st.slex.csplashscreen.feature.user.domain.UserInteractor -import st.slex.csplashscreen.feature.user.domain.UserInteractorImpl -import st.slex.csplashscreen.feature.user.navigation.UserRouter -import st.slex.csplashscreen.feature.user.navigation.UserRouterImpl -import st.slex.csplashscreen.feature.user.ui.presenter.UserViewModel - -@Module -interface UserModule { - - @Binds - @UserScope - fun bindRepository(impl: UserRepositoryImpl): UserRepository - - @Binds - @UserScope - fun bindsInteractor(impl: UserInteractorImpl): UserInteractor - - @Binds - @UserScope - fun bindsRouter(impl: UserRouterImpl): UserRouter - - @Binds - @IntoMap - @ViewModelKey(UserViewModel::class) - fun bindsViewModel(impl: UserViewModel): ViewModel - - @Binds - @UserScope - fun bindsViewModelFactory(impl: ViewModelFactory): ViewModelProvider.Factory -} \ No newline at end of file diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserScope.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserScope.kt deleted file mode 100644 index bc6b4add..00000000 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/di/UserScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package st.slex.csplashscreen.feature.user.di - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class UserScope \ No newline at end of file diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/domain/UserInteractorImpl.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/domain/UserInteractorImpl.kt index 048e6ddd..c2140fb3 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/domain/UserInteractorImpl.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/domain/UserInteractorImpl.kt @@ -10,9 +10,8 @@ import st.slex.csplashscreen.core.network.model.ui.ImageModel import st.slex.csplashscreen.core.network.model.ui.user.UserModel import st.slex.csplashscreen.core.photos.data.PhotosRepository import st.slex.csplashscreen.feature.user.data.UserRepository -import javax.inject.Inject -class UserInteractorImpl @Inject constructor( +class UserInteractorImpl( private val photosRepository: PhotosRepository, private val collectionsRepository: CollectionsRepository, private val userRepository: UserRepository 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 5943c3b1..9c0f1caf 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 @@ -12,47 +12,43 @@ 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.ui.utils.CollectAsEvent -import st.slex.csplashscreen.feature.user.di.UserComponentBuilder import st.slex.csplashscreen.feature.user.ui.UserScreen -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Action.Init -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Action.OnBackButtonClick -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Action.OnCollectionClick -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Action.OnImageClick -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Action.OnUserClick -import st.slex.csplashscreen.feature.user.ui.presenter.UserViewModel +import st.slex.csplashscreen.feature.user.ui.presenter.UserStore +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Action.Init +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Action.OnBackButtonClick +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Action.OnCollectionClick +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Action.OnImageClick +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Action.OnUserClick import st.slex.csplashscreen.feature.user.ui.state.rememberUserPagerState import st.slex.csplashscreen.feature.user.ui.state.rememberUserSwipeState fun NavGraphBuilder.userGraph( modifier: Modifier = Modifier, ) { - createScreen( - appDestination = AppDestination.USER, - featureBuilder = UserComponentBuilder - ) { viewModel: UserViewModel, args -> + createScreen(AppDestination.USER) { store: UserStore, args -> val arguments = args.firstOrNull() .orEmpty() .let(AppArguments::UserScreen) - val state by remember { viewModel.state }.collectAsState() + val state by remember { store.state }.collectAsState() val photos = remember { - viewModel.state.mapState { it.photos } + store.state.mapState { it.photos } }.collectAsLazyPagingItems() val likes = remember(arguments) { - viewModel.state.mapState { it.likes } + store.state.mapState { it.likes } }.collectAsLazyPagingItems() val collections = remember(arguments) { - viewModel.state.mapState { it.collections } + store.state.mapState { it.collections } }.collectAsLazyPagingItems() LaunchedEffect(arguments) { - viewModel.sendAction(Init(arguments)) + store.sendAction(Init(arguments)) } - viewModel.event.CollectAsEvent { event -> + store.event.CollectAsEvent { event -> // TODO NOT IMPLEMENTED YET } @@ -72,16 +68,16 @@ fun NavGraphBuilder.userGraph( userPagerState = userPagerState, userSwipeState = userSwipeState, onImageClick = remember { - { value -> viewModel.sendAction(OnImageClick(value)) } + { value -> store.sendAction(OnImageClick(value)) } }, onUserClick = remember { - { value -> viewModel.sendAction(OnUserClick(value)) } + { value -> store.sendAction(OnUserClick(value)) } }, onCollectionClick = remember { - { value -> viewModel.sendAction(OnCollectionClick(value)) } + { value -> store.sendAction(OnCollectionClick(value)) } }, popBackStack = remember { - { viewModel.sendAction(OnBackButtonClick) } + { store.sendAction(OnBackButtonClick) } }, ) } diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouter.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouter.kt index 000e5513..9f6d0ce5 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouter.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserRouter.kt @@ -1,6 +1,6 @@ package st.slex.csplashscreen.feature.user.navigation import st.slex.csplashscreen.core.ui.mvi.Router -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent -interface UserRouter : Router \ No newline at end of file +interface UserRouter : Router \ No newline at end of file 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 704625b9..5e2901b7 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 @@ -3,10 +3,9 @@ package st.slex.csplashscreen.feature.user.navigation 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 -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Navigation -import javax.inject.Inject +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Navigation -class UserRouterImpl @Inject constructor( +class UserRouterImpl( private val navigator: Navigator ) : UserRouter { diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/UserScreen.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/UserScreen.kt index 74f2afe2..e8cddd85 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/UserScreen.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/UserScreen.kt @@ -25,13 +25,13 @@ import st.slex.csplashscreen.feature.user.ui.components.pager.UserPager import st.slex.csplashscreen.feature.user.ui.components.toolbar.UserToolbar import st.slex.csplashscreen.feature.user.ui.state.UserPagerState import st.slex.csplashscreen.feature.user.ui.state.UserSwipeState -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent import st.slex.csplashscreen.feature.user.ui.utils.SwipeState @OptIn(ExperimentalMaterialApi::class) @Composable fun UserScreen( - state: UserStore.State, + state: UserStoreComponent.State, userPagerState: UserPagerState, userSwipeState: UserSwipeState, popBackStack: () -> Unit, 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 259ab83b..d730bdf9 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 @@ -1,72 +1,133 @@ package st.slex.csplashscreen.feature.user.ui.presenter -import androidx.compose.runtime.Stable +import androidx.paging.Pager +import androidx.paging.PagingConfig import androidx.paging.PagingData +import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.collection.ui.model.CollectionModel -import st.slex.csplashscreen.core.navigation.AppArguments -import st.slex.csplashscreen.core.network.model.ui.user.UserModel +import st.slex.csplashscreen.core.collection.ui.model.toPresentation +import st.slex.csplashscreen.core.core.coroutine.AppDispatcher import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.photos.ui.model.toPresentation import st.slex.csplashscreen.core.ui.mvi.Store - -interface UserStore { - - @Stable - data class State( - val user: UserModel?, - val photos: PagingData, - val likes: PagingData, - val collections: PagingData - ) : Store.State { - companion object { - val INITIAL = State( - user = null, - photos = PagingData.empty(), - likes = PagingData.empty(), - collections = PagingData.empty() - ) +import st.slex.csplashscreen.core.ui.paging.PagingSource +import st.slex.csplashscreen.feature.user.domain.UserInteractor +import st.slex.csplashscreen.feature.user.navigation.UserRouter +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Action +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Event +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.Navigation +import st.slex.csplashscreen.feature.user.ui.presenter.UserStoreComponent.State + +class UserStore( + private val interactor: UserInteractor, + appDispatcher: AppDispatcher, + router: UserRouter +) : Store( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { + + override fun sendAction(action: Action) { + when (action) { + is Action.Init -> actionInit(action) + is Action.OnBackButtonClick -> actionBackClick() + is Action.OnCollectionClick -> actionCollectionClick(action) + is Action.OnImageClick -> actionImageClick(action) + is Action.OnUserClick -> actionUserClick(action) } } - @Stable - sealed interface Event : Store.Event - - sealed interface Navigation : Store.Navigation { - - data object PopBack : Navigation - - data class User( - val username: String - ) : Navigation + private fun actionInit( + action: Action.Init + ) { + interactor + .getUser(action.args.username) + .launch { user -> + updateState { currentState -> + currentState.copy(user = user) + } + } + + getPhotos(action.args.username) + .launch { photos -> + updateState { currentState -> + currentState.copy(photos = photos) + } + } + + getLikes(action.args.username) + .launch { likes -> + updateState { currentState -> + currentState.copy(likes = likes) + } + } + + getCollections(action.args.username) + .launch { collections -> + updateState { currentState -> + currentState.copy(collections = collections) + } + } + } - data class Image( - val uuid: String - ) : Navigation + private fun getPhotos( + username: String + ): StateFlow> = Pager(pagingConfig) { + PagingSource { page, pageSize -> + interactor.getUserPhotos( + username = username, + page = page, + pageSize = pageSize + ).map { it.toPresentation() } + } + }.flow.state() + + private fun getLikes( + username: String + ): StateFlow> = Pager(pagingConfig) { + PagingSource { page, pageSize -> + interactor.getUserLikePhotos( + username = username, + page = page, + pageSize = pageSize + ).map { it.toPresentation() } + } + }.flow.state() + + private fun getCollections( + username: String + ): StateFlow> = Pager(pagingConfig) { + PagingSource { page, pageSize -> + interactor.getUserCollections( + username = username, + page = page, + pageSize = pageSize + ).map { it.toPresentation() } + } + }.flow.state() - data class Collection( - val uuid: String - ) : Navigation + private fun actionBackClick() { + navigate(Navigation.PopBack) } - @Stable - sealed interface Action : Store.Action { - - data class Init( - val args: AppArguments.UserScreen - ) : Action + private fun actionCollectionClick(action: Action.OnCollectionClick) { + navigate(Navigation.Collection(action.uuid)) + } - data object OnBackButtonClick : Action + private fun actionImageClick(action: Action.OnImageClick) { + navigate(Navigation.Image(action.uuid)) + } - data class OnUserClick( - val username: String - ) : Action + private fun actionUserClick(action: Action.OnUserClick) { + navigate(Navigation.User(action.username)) + } - data class OnImageClick( - val uuid: String - ) : Action + companion object { - data class OnCollectionClick( - val uuid: String - ) : Action + private val pagingConfig = PagingConfig( + pageSize = 10, + enablePlaceholders = false + ) } -} - +} \ No newline at end of file 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 new file mode 100644 index 00000000..ec6f701a --- /dev/null +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStoreComponent.kt @@ -0,0 +1,72 @@ +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.network.model.ui.user.UserModel +import st.slex.csplashscreen.core.photos.ui.model.PhotoModel +import st.slex.csplashscreen.core.ui.mvi.StoreComponent + +interface UserStoreComponent { + + @Stable + data class State( + val user: UserModel?, + val photos: PagingData, + val likes: PagingData, + val collections: PagingData + ) : StoreComponent.State { + companion object { + val INITIAL = State( + user = null, + photos = PagingData.empty(), + likes = PagingData.empty(), + collections = PagingData.empty() + ) + } + } + + @Stable + sealed interface Event : StoreComponent.Event + + sealed interface Navigation : StoreComponent.Navigation { + + data object PopBack : Navigation + + data class User( + val username: String + ) : Navigation + + data class Image( + val uuid: String + ) : Navigation + + data class Collection( + val uuid: String + ) : Navigation + } + + @Stable + sealed interface Action : StoreComponent.Action { + + data class Init( + val args: AppArguments.UserScreen + ) : Action + + data object OnBackButtonClick : Action + + data class OnUserClick( + val username: String + ) : Action + + data class OnImageClick( + val uuid: String + ) : Action + + data class OnCollectionClick( + val uuid: String + ) : Action + } +} + diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt deleted file mode 100644 index a70a4ec1..00000000 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt +++ /dev/null @@ -1,134 +0,0 @@ -package st.slex.csplashscreen.feature.user.ui.presenter - -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingData -import kotlinx.coroutines.flow.StateFlow -import st.slex.csplashscreen.core.collection.ui.model.CollectionModel -import st.slex.csplashscreen.core.collection.ui.model.toPresentation -import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.photos.ui.model.PhotoModel -import st.slex.csplashscreen.core.photos.ui.model.toPresentation -import st.slex.csplashscreen.core.ui.mvi.BaseViewModel -import st.slex.csplashscreen.core.ui.paging.PagingSource -import st.slex.csplashscreen.feature.user.domain.UserInteractor -import st.slex.csplashscreen.feature.user.navigation.UserRouter -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Action -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Event -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.Navigation -import st.slex.csplashscreen.feature.user.ui.presenter.UserStore.State -import javax.inject.Inject - -class UserViewModel @Inject constructor( - private val interactor: UserInteractor, - appDispatcher: AppDispatcher, - router: UserRouter -) : BaseViewModel( - router = router, - appDispatcher = appDispatcher, - initialState = State.INITIAL -) { - - override fun sendAction(action: Action) { - when (action) { - is Action.Init -> actionInit(action) - is Action.OnBackButtonClick -> actionBackClick() - is Action.OnCollectionClick -> actionCollectionClick(action) - is Action.OnImageClick -> actionImageClick(action) - is Action.OnUserClick -> actionUserClick(action) - } - } - - private fun actionInit( - action: Action.Init - ) { - interactor - .getUser(action.args.username) - .launch { user -> - updateState { currentState -> - currentState.copy(user = user) - } - } - - getPhotos(action.args.username) - .launch { photos -> - updateState { currentState -> - currentState.copy(photos = photos) - } - } - - getLikes(action.args.username) - .launch { likes -> - updateState { currentState -> - currentState.copy(likes = likes) - } - } - - getCollections(action.args.username) - .launch { collections -> - updateState { currentState -> - currentState.copy(collections = collections) - } - } - } - - private fun getPhotos( - username: String - ): StateFlow> = Pager(pagingConfig) { - PagingSource { page, pageSize -> - interactor.getUserPhotos( - username = username, - page = page, - pageSize = pageSize - ).map { it.toPresentation() } - } - }.flow.state() - - private fun getLikes( - username: String - ): StateFlow> = Pager(pagingConfig) { - PagingSource { page, pageSize -> - interactor.getUserLikePhotos( - username = username, - page = page, - pageSize = pageSize - ).map { it.toPresentation() } - } - }.flow.state() - - private fun getCollections( - username: String - ): StateFlow> = Pager(pagingConfig) { - PagingSource { page, pageSize -> - interactor.getUserCollections( - username = username, - page = page, - pageSize = pageSize - ).map { it.toPresentation() } - } - }.flow.state() - - private fun actionBackClick() { - navigate(Navigation.PopBack) - } - - private fun actionCollectionClick(action: Action.OnCollectionClick) { - navigate(Navigation.Collection(action.uuid)) - } - - private fun actionImageClick(action: Action.OnImageClick) { - navigate(Navigation.Image(action.uuid)) - } - - private fun actionUserClick(action: Action.OnUserClick) { - navigate(Navigation.User(action.username)) - } - - companion object { - - private val pagingConfig = PagingConfig( - pageSize = 10, - enablePlaceholders = false - ) - } -} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bb7fe472..1904a94a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,8 +23,7 @@ accompanist = "0.30.0" coilCompose = "2.5.0" composeActivity = "1.9.0" -koinAndroid = "3.5.6" -koinCompose = "1.1.5" +koin = "3.5.6" koinKsp = "1.3.1" ktor = "2.3.6" @@ -41,8 +40,6 @@ room = "2.6.1" ksp = "1.9.23-1.0.19" mockito = "2.19.0" -dagger = "2.48" - [libraries] android-desugarJdkLibs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" } android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" } @@ -108,14 +105,18 @@ androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } androidx-room-testing = { group = "androidx.room", name = "room-testing", version.ref = "room" } -dagger-core = { group = "com.google.dagger", name = "dagger", version.ref = "dagger" } -dagger-compiler = { group = "com.google.dagger", name = "dagger-compiler", version.ref = "dagger" } - -koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koinAndroid" } -koin-compose = { group = "io.insert-koin", name = "koin-compose", version.ref = "koinCompose" } +koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } +koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } +koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" } koin-annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koinKsp" } + +koin-test-core = { module = "io.insert-koin:koin-test", version.ref = "koin" } +koin-test-junit = { module = "io.insert-koin:koin-test-junit4", version.ref = "koin" } + koin-ksp = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koinKsp" } +coroutine-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version = "1.7.3" } + [plugins] kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } @@ -129,6 +130,12 @@ lifecycle = [ "lifecycle-viewModel" ] +koin = [ + "koin-core", + "koin-android", + "koin-annotations" +] + accompanist = [ "accompanist-placeholder", "accompanist-systemuicontroller", @@ -172,7 +179,10 @@ test = [ "mockito", "junit", "robolectric", - "androidx-test" + "androidx-test", + "koin-test-core", + "koin-test-junit", + "coroutine-test" ] room = [