From 8015b065e39891c97baa236acb0745a820f198bd Mon Sep 17 00:00:00 2001 From: Diego Beraldin Date: Fri, 4 Aug 2023 15:18:57 +0200 Subject: [PATCH] feat(search): implement community list --- README.md | 33 ++-- core-api/core_api.podspec | 39 ++++ .../core/api/dto/SearchResponse.kt | 13 ++ .../core/api/dto/SearchType.kt | 23 +++ .../api/provider/DefaultServiceProvider.kt | 5 + .../core/api/provider/ServiceProvider.kt | 2 + .../core/api/service/CommunityService.kt | 6 +- .../core/api/service/SearchService.kt | 25 +++ .../core/api/service/SiteService.kt | 2 +- .../core/api/service/UserService.kt | 2 +- core-appearance/core_appearance.podspec | 39 ++++ core-architecture/core_architecture.podspec | 39 ++++ core-commonui/core_commonui.podspec | 39 ++++ .../postdetail/PostDetailScreenViewModel.kt | 2 +- core-preferences/core_preferences.podspec | 39 ++++ core-utils/core_utils.podspec | 39 ++++ domain-identity/domain_identity.podspec | 39 ++++ .../domain/lemmy/data/CommunityModel.kt | 1 + .../lemmy/repository/CommentRepository.kt | 2 +- .../lemmy/repository/CommunityRepository.kt | 34 +++- .../lemmy/repository/PostsRepository.kt | 2 +- .../domain/lemmy/repository/SiteRepository.kt | 2 +- .../domain/lemmy/repository/UserRepository.kt | 12 +- .../domain/lemmy/repository/utils/Mappings.kt | 10 ++ .../feature/home/viewmodel/HomeScreenModel.kt | 2 +- .../comments/ProfileCommentsViewModel.kt | 2 +- .../logged/posts/ProfilePostsViewModel.kt | 2 +- feature-search/build.gradle.kts | 9 +- .../feature/search/SearchModule.kt | 18 -- .../feature/search/di/Utils.kt | 9 + .../feature/search/SearchModule.kt | 7 - .../feature/search/SearchScreenModel.kt | 10 -- .../feature/search/SearchScreenMviModel.kt | 12 -- .../feature/search/SearchTab.kt | 53 ------ .../feature/search/di/SearchModule.kt | 17 ++ .../feature/search/di/Utils.kt | 5 + .../feature/search/ui/CommunityItem.kt | 84 +++++++++ .../feature/search/ui/SearchTab.kt | 168 ++++++++++++++++++ .../search/viewmodel/SearchScreenModel.kt | 126 +++++++++++++ .../search/viewmodel/SearchScreenMviModel.kt | 28 +++ .../feature/search/SearchModule.kt | 20 --- .../feature/search/di/Utils.kt | 11 ++ .../commonMain/resources/MR/base/strings.xml | 4 + .../commonMain/resources/MR/it/strings.xml | 4 + .../diegoberaldin/raccoonforlemmy/DiHelper.kt | 2 +- .../diegoberaldin/raccoonforlemmy/App.kt | 2 +- .../diegoberaldin/raccoonforlemmy/DiHelper.kt | 2 +- 47 files changed, 890 insertions(+), 156 deletions(-) create mode 100644 core-api/core_api.podspec create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchResponse.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchType.kt create mode 100644 core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt create mode 100644 core-appearance/core_appearance.podspec create mode 100644 core-architecture/core_architecture.podspec create mode 100644 core-commonui/core_commonui.podspec create mode 100644 core-preferences/core_preferences.podspec create mode 100644 core-utils/core_utils.podspec create mode 100644 domain-identity/domain_identity.podspec delete mode 100644 feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt create mode 100644 feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt delete mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt delete mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenModel.kt delete mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenMviModel.kt delete mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchTab.kt create mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/SearchModule.kt create mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt create mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/CommunityItem.kt create mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/SearchTab.kt create mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenModel.kt create mode 100644 feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenMviModel.kt delete mode 100644 feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt create mode 100644 feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt diff --git a/README.md b/README.md index e712f27d3..5be2dd717 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Raccon for Lemmy + A Kotlin Multiplatform Mobile client for Lemmy.
@@ -14,21 +15,29 @@ A Kotlin Multiplatform Mobile client for Lemmy.
-This is mostly an exercise to play around with KMM and Compose Multiplatform and implement a Lemmy client. +This is mostly an exercise to play around with KMM and Compose Multiplatform and implement a Lemmy +client. -The project is still at an early stage and not ready for production, expect things to change and even major changes to the source code. +The project is still at an early stage and not ready for production, expect things to change and +even major changes to the source code. Libraries used: -- Koin for dependency injection -- Voyager for screen navigation -- Ktor with Ktorfit for networking in conjunction with kotlinx-serialization for JSON marshalling -- Moko resources for resource management -- Kamel for lazy image loading -- Multiplatform settings for encrypted preferences -- Markdown by Jetbrains for markdown parsing +- [Koin](https://github.com/InsertKoinIO/koin) for dependency injection +- [Voyager](https://github.com/adrielcafe/voyager) for screen navigation +- [Ktor](https://github.com/ktorio/ktor) with [Ktorfit](https://github.com/Foso/Ktorfit) for + networking in conjunction with kotlinx-serialization for JSON marshalling +- [Moko resources](https://github.com/icerockdev/moko-resources) for resource management +- [Kamel](https://github.com/Kamel-Media/Kamel) for lazy image loading +- [Multiplatform settings](https://github.com/russhwolf/multiplatform-settings) for encrypted + preferences +- [Markdown](https://github.com/JetBrains/markdown) for markdown parsing - ... more to come (e.g. SQLdelight for persistence) -Credits: -- the `core-api` module is heavily inspired by [Jerboa for Lemmy](https://github.com/dessalines/jerboa) -- the `core-md` module is copied from [Multiplatform Markdown Renderer](https://github.com/mikepenz/multiplatform-markdown-renderer) +Credits: + +- the `core-api` module is heavily inspired + by [Jerboa for Lemmy](https://github.com/dessalines/jerboa) +- the `core-md` module is copied + from [Multiplatform Markdown Renderer](https://github.com/mikepenz/multiplatform-markdown-renderer) +- the UI is vaguely inspired by the [Thunder](https://github.com/thunder-app/thunder) app diff --git a/core-api/core_api.podspec b/core-api/core_api.podspec new file mode 100644 index 000000000..cb3a85412 --- /dev/null +++ b/core-api/core_api.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |spec| + spec.name = 'core_api' + spec.version = '1.0' + spec.homepage = 'Link to the Shared Module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for the Shared Module' + spec.vendored_frameworks = 'build/cocoapods/framework/core-api.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '14.1' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':core-api', + 'PRODUCT_MODULE_NAME' => 'core-api', + } + + spec.script_phases = [ + { + :name => 'Build core_api', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchResponse.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchResponse.kt new file mode 100644 index 000000000..f8cbd7786 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchResponse.kt @@ -0,0 +1,13 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.api.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SearchResponse( + @SerialName("type_") val type: SearchType, + @SerialName("comments") val comments: List, + @SerialName("posts") val posts: List, + @SerialName("communities") val communities: List, + @SerialName("users") val users: List, +) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchType.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchType.kt new file mode 100644 index 000000000..b54252e74 --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/dto/SearchType.kt @@ -0,0 +1,23 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.api.dto + +import kotlinx.serialization.SerialName + +enum class SearchType { + @SerialName("All") + All, + + @SerialName("Comments") + Comments, + + @SerialName("Posts") + Posts, + + @SerialName("Communities") + Communities, + + @SerialName("Users") + Users, + + @SerialName("Url") + Url, +} diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/DefaultServiceProvider.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/DefaultServiceProvider.kt index f76121f3f..cd7ddcd07 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/DefaultServiceProvider.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/DefaultServiceProvider.kt @@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.service.AuthService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.CommentService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.CommunityService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.PostService +import com.github.diegoberaldin.raccoonforlemmy.core.api.service.SearchService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.SiteService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.UserService import de.jensklingenberg.ktorfit.Ktorfit @@ -43,6 +44,9 @@ internal class DefaultServiceProvider : ServiceProvider { override lateinit var comment: CommentService private set + override lateinit var search: SearchService + private set + private val baseUrl: String get() = "https://$currentInstance/api/$VERSION/" private val client = HttpClient { defaultRequest { @@ -79,5 +83,6 @@ internal class DefaultServiceProvider : ServiceProvider { user = ktorfit.create() site = ktorfit.create() comment = ktorfit.create() + search = ktorfit.create() } } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/ServiceProvider.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/ServiceProvider.kt index 307dd8410..ec7cb54df 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/ServiceProvider.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/provider/ServiceProvider.kt @@ -4,6 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.service.AuthService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.CommentService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.CommunityService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.PostService +import com.github.diegoberaldin.raccoonforlemmy.core.api.service.SearchService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.SiteService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.UserService @@ -16,6 +17,7 @@ interface ServiceProvider { val user: UserService val site: SiteService val comment: CommentService + val search: SearchService fun changeInstance(value: String) } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt index c0fbd7f87..c059ab538 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/CommunityService.kt @@ -14,15 +14,15 @@ import de.jensklingenberg.ktorfit.http.Query interface CommunityService { @GET("community") - suspend fun getCommunity( + suspend fun get( @Query("auth") auth: String? = null, @Query("id") id: Int? = null, @Query("name") name: String? = null, ): Response @POST("community/follow") - suspend fun followCommunity(@Body form: FollowCommunityForm): Response + suspend fun follow(@Body form: FollowCommunityForm): Response @POST("community/block") - suspend fun blockCommunity(@Body form: BlockCommunityForm): Response + suspend fun block(@Body form: BlockCommunityForm): Response } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt new file mode 100644 index 000000000..72c29b2fe --- /dev/null +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SearchService.kt @@ -0,0 +1,25 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.api.service + +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SearchResponse +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SearchType +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SortType +import de.jensklingenberg.ktorfit.Response +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Query + +interface SearchService { + @GET("search") + suspend fun search( + @Query("q") q: String, + @Query("community_id") communityId: Int? = null, + @Query("community_name") communityName: String? = null, + @Query("creator_id") creatorId: Int? = null, + @Query("type_") type: SearchType? = null, + @Query("sort") sort: SortType? = null, + @Query("listing_type") listingType: ListingType? = null, + @Query("page") page: Int? = null, + @Query("limit") limit: Int? = null, + @Query("auth") auth: String? = null, + ): Response +} diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt index 9923b76c2..5b0b9d735 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/SiteService.kt @@ -7,7 +7,7 @@ import de.jensklingenberg.ktorfit.http.Query interface SiteService { @GET("site") - suspend fun getSite( + suspend fun get( @Query("auth") auth: String? = null, ): Response } diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt index 199baaf2b..9f57fb9df 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/service/UserService.kt @@ -9,7 +9,7 @@ import de.jensklingenberg.ktorfit.http.Query interface UserService { @GET("user") - suspend fun getPersonDetails( + suspend fun getDetails( @Query("auth") auth: String? = null, @Query("community_id") communityId: Int? = null, @Query("person_id") personId: Int? = null, diff --git a/core-appearance/core_appearance.podspec b/core-appearance/core_appearance.podspec new file mode 100644 index 000000000..f170165dc --- /dev/null +++ b/core-appearance/core_appearance.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |spec| + spec.name = 'core_appearance' + spec.version = '1.0.0' + spec.homepage = 'Link to the Shared Module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for the Shared Module' + spec.vendored_frameworks = 'build/cocoapods/framework/core-appearance.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '14.1' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':core-appearance', + 'PRODUCT_MODULE_NAME' => 'core-appearance', + } + + spec.script_phases = [ + { + :name => 'Build core_appearance', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/core-architecture/core_architecture.podspec b/core-architecture/core_architecture.podspec new file mode 100644 index 000000000..e1a4d89bc --- /dev/null +++ b/core-architecture/core_architecture.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |spec| + spec.name = 'core_architecture' + spec.version = '1.0' + spec.homepage = 'Link to the Shared Module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for the Shared Module' + spec.vendored_frameworks = 'build/cocoapods/framework/core-architecture.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '14.1' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':core-architecture', + 'PRODUCT_MODULE_NAME' => 'core-architecture', + } + + spec.script_phases = [ + { + :name => 'Build core_architecture', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/core-commonui/core_commonui.podspec b/core-commonui/core_commonui.podspec new file mode 100644 index 000000000..374766df4 --- /dev/null +++ b/core-commonui/core_commonui.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |spec| + spec.name = 'core_commonui' + spec.version = '1.0' + spec.homepage = 'Link to the Shared Module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for the Shared Module' + spec.vendored_frameworks = 'build/cocoapods/framework/core-commonui.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '14.1' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':core-commonui', + 'PRODUCT_MODULE_NAME' => 'core-commonui', + } + + spec.script_phases = [ + { + :name => 'Build core_commonui', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreenViewModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreenViewModel.kt index 10267a9bb..9210821bd 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreenViewModel.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreenViewModel.kt @@ -86,7 +86,7 @@ class PostDetailScreenViewModel( val auth = identityRepository.authToken.value val refreshing = currentState.refreshing val sort = keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType() - val commentList = commentRepository.getComments( + val commentList = commentRepository.getAll( auth = auth, postId = post.id, page = currentPage, diff --git a/core-preferences/core_preferences.podspec b/core-preferences/core_preferences.podspec new file mode 100644 index 000000000..b9dcde5fe --- /dev/null +++ b/core-preferences/core_preferences.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |spec| + spec.name = 'core_preferences' + spec.version = '1.0.0' + spec.homepage = 'Link to the Shared Module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for the Shared Module' + spec.vendored_frameworks = 'build/cocoapods/framework/core-preferences.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '14.1' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':core-preferences', + 'PRODUCT_MODULE_NAME' => 'core-preferences', + } + + spec.script_phases = [ + { + :name => 'Build core_preferences', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/core-utils/core_utils.podspec b/core-utils/core_utils.podspec new file mode 100644 index 000000000..06d49c2ff --- /dev/null +++ b/core-utils/core_utils.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |spec| + spec.name = 'core_utils' + spec.version = '1.0.0' + spec.homepage = 'Link to the Shared Module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for the Shared Module' + spec.vendored_frameworks = 'build/cocoapods/framework/core-utils.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '14.1' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':core-utils', + 'PRODUCT_MODULE_NAME' => 'core-utils', + } + + spec.script_phases = [ + { + :name => 'Build core_utils', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/domain-identity/domain_identity.podspec b/domain-identity/domain_identity.podspec new file mode 100644 index 000000000..031f21698 --- /dev/null +++ b/domain-identity/domain_identity.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |spec| + spec.name = 'domain_identity' + spec.version = '1.0' + spec.homepage = 'Link to the Shared Module homepage' + spec.source = { :http=> ''} + spec.authors = '' + spec.license = '' + spec.summary = 'Some description for the Shared Module' + spec.vendored_frameworks = 'build/cocoapods/framework/domain-identity.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '14.1' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':domain-identity', + 'PRODUCT_MODULE_NAME' => 'domain-identity', + } + + spec.script_phases = [ + { + :name => 'Build domain_identity', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt index 7e2849512..b7263e04c 100644 --- a/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt +++ b/domain-lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/CommunityModel.kt @@ -3,6 +3,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data data class CommunityModel( val id: Int = 0, val name: String = "", + val title: String = "", val host: String = "", val icon: String? = null, ) diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt index a3f792f8f..9db585441 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommentRepository.kt @@ -16,7 +16,7 @@ class CommentRepository( const val DEFAULT_PAGE_SIZE = 20 } - suspend fun getComments( + suspend fun getAll( postId: Int, auth: String? = null, page: Int, diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt index e8247092c..26bac86b4 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/CommunityRepository.kt @@ -1,6 +1,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommunityView +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.SearchType import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel @@ -9,11 +10,40 @@ class CommunityRepository( private val services: ServiceProvider, ) { - suspend fun getCommunity( + companion object { + const val DEFAULT_PAGE_SIZE = 20 + } + + suspend fun getAll( + query: String = "", + auth: String? = null, + page: Int, + limit: Int = DEFAULT_PAGE_SIZE, + ): List { + val response = services.search.search( + q = query, + auth = auth, + page = page, + limit = limit, + type = SearchType.Communities, + ).body() + return response?.communities?.map { + it.toModel() + }.orEmpty() + } + + suspend fun getSubscribed( + auth: String? = null, + ): List { + val response = services.site.get(auth).body() + return response?.myUser?.follows?.map { it.toModel() }.orEmpty() + } + + suspend fun get( auth: String? = null, id: Int, ): CommunityModel? { - val response = services.community.getCommunity( + val response = services.community.get( auth = auth, id = id, ).body() diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostsRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostsRepository.kt index 9a4679549..c4923117a 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostsRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PostsRepository.kt @@ -17,7 +17,7 @@ class PostsRepository( const val DEFAULT_PAGE_SIZE = 20 } - suspend fun getPosts( + suspend fun getAll( auth: String? = null, page: Int, limit: Int = DEFAULT_PAGE_SIZE, diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt index b72ff0f3f..7fb6b9344 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/SiteRepository.kt @@ -8,7 +8,7 @@ class SiteRepository( private val serviceProvider: ServiceProvider, ) { suspend fun getCurrentUser(auth: String): UserModel? { - val response = serviceProvider.site.getSite( + val response = serviceProvider.site.get( auth = auth, ) return response.body()?.myUser?.let { diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt index 285fcd492..1812160f7 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/UserRepository.kt @@ -13,11 +13,11 @@ class UserRepository( private val serviceProvider: ServiceProvider, ) { - suspend fun getUser( + suspend fun get( id: Int, auth: String? = null, ): UserModel? { - val response = serviceProvider.user.getPersonDetails( + val response = serviceProvider.user.getDetails( auth = auth, personId = id, ) @@ -31,7 +31,7 @@ class UserRepository( ) } - suspend fun getUserPosts( + suspend fun getPosts( id: Int, auth: String? = null, page: Int, @@ -39,7 +39,7 @@ class UserRepository( sort: SortType = SortType.Active, savedOnly: Boolean = false, ): List { - val response = serviceProvider.user.getPersonDetails( + val response = serviceProvider.user.getDetails( auth = auth, personId = id, page = page, @@ -51,14 +51,14 @@ class UserRepository( return dto.posts.map { it.toModel() } } - suspend fun getUserComments( + suspend fun getComments( id: Int, auth: String? = null, page: Int, limit: Int = PostsRepository.DEFAULT_PAGE_SIZE, sort: SortType = SortType.Active, ): List { - val response = serviceProvider.user.getPersonDetails( + val response = serviceProvider.user.getDetails( auth = auth, personId = id, page = page, diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt index 5e097e598..2e62a4594 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommentView import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.Community +import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.CommunityFollowerView import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.All import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.Local import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.ListingType.Subscribed @@ -88,10 +89,19 @@ internal fun CommentView.toModel() = CommentModel( internal fun Community.toModel() = CommunityModel( id = id, name = name, + title = title, icon = icon, host = actorId.toHost(), ) +internal fun CommunityFollowerView.toModel() = CommunityModel( + id = community.id, + name = community.name, + title = community.title, + icon = community.icon, + host = community.actorId.toHost(), +) + internal fun String.toHost(): String = this.replace("https://", "").let { val i = it.indexOf("/") it.substring(0, i) diff --git a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/viewmodel/HomeScreenModel.kt b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/viewmodel/HomeScreenModel.kt index 9cceccc6d..6f29df901 100644 --- a/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/viewmodel/HomeScreenModel.kt +++ b/feature-home/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/home/viewmodel/HomeScreenModel.kt @@ -102,7 +102,7 @@ class HomeScreenModel( val type = currentState.listingType val sort = currentState.sortType val refreshing = currentState.refreshing - val postList = postsRepository.getPosts( + val postList = postsRepository.getAll( auth = auth, page = currentPage, type = type, diff --git a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/comments/ProfileCommentsViewModel.kt b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/comments/ProfileCommentsViewModel.kt index a7c8306bf..53da163bb 100644 --- a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/comments/ProfileCommentsViewModel.kt +++ b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/comments/ProfileCommentsViewModel.kt @@ -49,7 +49,7 @@ class ProfileCommentsViewModel( mvi.updateState { it.copy(loading = true) } val auth = identityRepository.authToken.value val refreshing = currentState.refreshing - val commentList = userRepository.getUserComments( + val commentList = userRepository.getComments( auth = auth, id = user.id, page = currentPage, diff --git a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/posts/ProfilePostsViewModel.kt b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/posts/ProfilePostsViewModel.kt index 3f5573e02..6cf15b2b9 100644 --- a/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/posts/ProfilePostsViewModel.kt +++ b/feature-profile/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/profile/content/logged/posts/ProfilePostsViewModel.kt @@ -50,7 +50,7 @@ class ProfilePostsViewModel( mvi.updateState { it.copy(loading = true) } val auth = identityRepository.authToken.value val refreshing = currentState.refreshing - val postList = userRepository.getUserPosts( + val postList = userRepository.getPosts( auth = auth, id = user.id, savedOnly = savedOnly, diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index b7c35f708..b3caac457 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -41,13 +41,20 @@ kotlin { implementation(compose.materialIconsExtended) @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) implementation(compose.components.resources) + implementation(compose.material) implementation(libs.voyager.navigator) implementation(libs.voyager.tab) + implementation(libs.kamel) - implementation(projects.resources) implementation(projects.coreArchitecture) implementation(projects.coreAppearance) + + implementation(projects.domainIdentity) + implementation(projects.domainLemmy.data) + implementation(projects.domainLemmy.repository) + + implementation(projects.resources) } } val commonTest by getting { diff --git a/feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt b/feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt deleted file mode 100644 index 415442155..000000000 --- a/feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.feature.search - -import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel -import org.koin.dsl.module -import org.koin.java.KoinJavaComponent.inject - -actual val searchTabModule = module { - factory { - SearchScreenModel( - mvi = DefaultMviModel(SearchScreenMviModel.UiState()), - ) - } -} - -actual fun getSearchScreenModel(): SearchScreenModel { - val res: SearchScreenModel by inject(SearchScreenModel::class.java) - return res -} diff --git a/feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt b/feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt new file mode 100644 index 000000000..f8c675f4d --- /dev/null +++ b/feature-search/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt @@ -0,0 +1,9 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.di + +import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel +import org.koin.java.KoinJavaComponent.inject + +actual fun getSearchScreenModel(): SearchScreenModel { + val res: SearchScreenModel by inject(SearchScreenModel::class.java) + return res +} diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt deleted file mode 100644 index ed8296c0b..000000000 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.feature.search - -import org.koin.core.module.Module - -expect val searchTabModule: Module - -expect fun getSearchScreenModel(): SearchScreenModel diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenModel.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenModel.kt deleted file mode 100644 index 2df9f2207..000000000 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.feature.search - -import cafe.adriel.voyager.core.model.ScreenModel -import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel -import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel - -class SearchScreenModel( - private val mvi: DefaultMviModel, -) : ScreenModel, - MviModel by mvi diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenMviModel.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenMviModel.kt deleted file mode 100644 index 35d365a0a..000000000 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchScreenMviModel.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.feature.search - -import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel - -interface SearchScreenMviModel : - MviModel { - sealed interface Intent - - data class UiState(val loading: Boolean = false) - - sealed interface Effect -} diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchTab.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchTab.kt deleted file mode 100644 index 0b6e642ff..000000000 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchTab.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.feature.search - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Explore -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.rememberVectorPainter -import cafe.adriel.voyager.core.model.rememberScreenModel -import cafe.adriel.voyager.navigator.tab.Tab -import cafe.adriel.voyager.navigator.tab.TabOptions -import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing -import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle -import com.github.diegoberaldin.raccoonforlemmy.resources.MR -import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository -import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString -import dev.icerock.moko.resources.desc.desc - -object SearchTab : Tab { - - override val options: TabOptions - @Composable - get() { - val icon = rememberVectorPainter(Icons.Default.Explore) - val languageRepository = remember { getLanguageRepository() } - val lang by languageRepository.currentLanguage.collectAsState() - return remember(lang) { - val title = staticString(MR.strings.navigation_search.desc()) - TabOptions( - index = 1u, - title = title, - icon = icon, - ) - } - } - - @Composable - override fun Content() { - val model = rememberScreenModel { getSearchScreenModel() } - model.bindToLifecycle(key) - - Column(modifier = Modifier.padding(Spacing.xs)) { - Text( - text = "Search content", - ) - } - } -} diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/SearchModule.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/SearchModule.kt new file mode 100644 index 000000000..3f694f96e --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/SearchModule.kt @@ -0,0 +1,17 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.di + +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel +import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel +import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenMviModel +import org.koin.dsl.module + +val searchTabModule = module { + factory { + SearchScreenModel( + mvi = DefaultMviModel(SearchScreenMviModel.UiState()), + apiConfigRepository = get(), + identityRepository = get(), + communityRepository = get(), + ) + } +} diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt new file mode 100644 index 000000000..0b7c15d54 --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt @@ -0,0 +1,5 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.di + +import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel + +expect fun getSearchScreenModel(): SearchScreenModel \ No newline at end of file diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/CommunityItem.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/CommunityItem.kt new file mode 100644 index 000000000..92f98c0db --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/CommunityItem.kt @@ -0,0 +1,84 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel +import io.kamel.image.KamelImage +import io.kamel.image.asyncPainterResource + +@Composable +internal fun CommunityItem( + community: CommunityModel, + modifier: Modifier = Modifier, +) { + val title = community.title + val communityName = community.name + val communityIcon = community.icon.orEmpty() + val communityHost = community.host + val iconSize = 30.dp + Row( + modifier = modifier.padding( + vertical = Spacing.xs, + horizontal = Spacing.s, + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(Spacing.xs), + ) { + if (communityIcon.isNotEmpty()) { + val painterResource = asyncPainterResource(data = communityIcon) + KamelImage( + modifier = Modifier.padding(Spacing.xxxs).size(iconSize) + .clip(RoundedCornerShape(iconSize / 2)), + resource = painterResource, + contentDescription = null, + contentScale = ContentScale.FillBounds, + ) + } else { + Box( + modifier = Modifier.padding(Spacing.xxxs).size(iconSize) + .background(MaterialTheme.colorScheme.primary) + .clip(RoundedCornerShape(iconSize / 2)), + contentAlignment = Alignment.Center, + ) { + Text( + text = community.name.firstOrNull()?.toString().orEmpty(), + style = MaterialTheme.typography.headlineMedium, + color = MaterialTheme.colorScheme.onPrimary, + ) + } + } + Column { + Text( + text = buildString { + append(title) + }, + style = MaterialTheme.typography.bodyLarge, + ) + Text( + text = buildString { + append("!") + append(communityName) + if (communityHost.isNotEmpty()) { + append("@$communityHost") + } + }, + style = MaterialTheme.typography.bodySmall, + ) + } + } +} diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/SearchTab.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/SearchTab.kt new file mode 100644 index 000000000..b36c65db4 --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/ui/SearchTab.kt @@ -0,0 +1,168 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Explore +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.material3.Button +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CheckboxDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.model.rememberScreenModel +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.navigator.tab.TabOptions +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle +import com.github.diegoberaldin.raccoonforlemmy.feature.search.di.getSearchScreenModel +import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenMviModel +import com.github.diegoberaldin.raccoonforlemmy.resources.MR +import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository +import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString +import dev.icerock.moko.resources.compose.stringResource +import dev.icerock.moko.resources.desc.desc + +object SearchTab : Tab { + + override val options: TabOptions + @Composable get() { + val icon = rememberVectorPainter(Icons.Default.Explore) + val languageRepository = remember { getLanguageRepository() } + val lang by languageRepository.currentLanguage.collectAsState() + return remember(lang) { + val title = staticString(MR.strings.navigation_search.desc()) + TabOptions( + index = 1u, + title = title, + icon = icon, + ) + } + } + + @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class) + @Composable + override fun Content() { + val model = rememberScreenModel { getSearchScreenModel() } + model.bindToLifecycle(key) + val uiState by model.uiState.collectAsState() + + Column( + modifier = Modifier.padding(Spacing.xxs), + verticalArrangement = Arrangement.spacedBy(Spacing.xxs), + ) { + TextField( + modifier = Modifier.padding( + horizontal = Spacing.m, + vertical = Spacing.s, + ).fillMaxWidth(), + label = { + Text(text = stringResource(MR.strings.explore_search_placeholder)) + }, + singleLine = true, + value = uiState.searchText, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + ), + onValueChange = { value -> + model.reduce(SearchScreenMviModel.Intent.SetSearch(value)) + }, + ) + Row( + modifier = Modifier.padding(horizontal = Spacing.xxs), + verticalAlignment = Alignment.CenterVertically, + ) { + if (uiState.isLogged) { + Checkbox( + checked = uiState.subscribedOnly, + onCheckedChange = { + model.reduce(SearchScreenMviModel.Intent.SetSubscribedOnly(it)) + }, + colors = CheckboxDefaults.colors(checkedColor = MaterialTheme.colorScheme.primary), + ) + Text( + text = stringResource(MR.strings.explore_subscribed_only), + style = MaterialTheme.typography.labelMedium, + ) + } + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + model.reduce(SearchScreenMviModel.Intent.SearchFired) + }) { + Text( + text = stringResource(MR.strings.button_search), + style = MaterialTheme.typography.labelMedium, + ) + } + } + + val pullRefreshState = rememberPullRefreshState(uiState.refreshing, { + model.reduce(SearchScreenMviModel.Intent.Refresh) + }) + Box( + modifier = Modifier.padding(Spacing.xxs).pullRefresh(pullRefreshState), + ) { + LazyColumn( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(Spacing.xs), + ) { + items(uiState.communities) { community -> + CommunityItem( + modifier = Modifier.fillMaxWidth(), + community = community, + ) + } + item { + if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) { + model.reduce(SearchScreenMviModel.Intent.LoadNextPage) + } + if (uiState.loading && !uiState.refreshing) { + Box( + modifier = Modifier.fillMaxWidth().padding(Spacing.xs), + contentAlignment = Alignment.Center, + ) { + CircularProgressIndicator( + modifier = Modifier.size(25.dp), + color = MaterialTheme.colorScheme.primary, + ) + } + } + } + } + + PullRefreshIndicator( + refreshing = uiState.refreshing, + state = pullRefreshState, + modifier = Modifier.align(Alignment.TopCenter), + backgroundColor = MaterialTheme.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.onSurface, + ) + } + } + } +} diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenModel.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenModel.kt new file mode 100644 index 000000000..0b5bf4b80 --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenModel.kt @@ -0,0 +1,126 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel + +import cafe.adriel.voyager.core.model.ScreenModel +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel +import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiConfigurationRepository +import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostsRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch + +class SearchScreenModel( + private val mvi: DefaultMviModel, + private val apiConfigRepository: ApiConfigurationRepository, + private val identityRepository: IdentityRepository, + private val communityRepository: CommunityRepository, +) : ScreenModel, + MviModel by mvi { + + private var currentPage: Int = 1 + + override fun onStarted() { + mvi.onStarted() + mvi.updateState { + it.copy( + instance = apiConfigRepository.getInstance(), + ) + } + mvi.scope.launch { + identityRepository.authToken.map { !it.isNullOrEmpty() }.onEach { isLogged -> + mvi.updateState { + it.copy(isLogged = isLogged) + } + }.launchIn(this) + } + + refresh() + } + + override fun reduce(intent: SearchScreenMviModel.Intent) { + when (intent) { + SearchScreenMviModel.Intent.LoadNextPage -> loadNextPage() + SearchScreenMviModel.Intent.Refresh -> refresh() + SearchScreenMviModel.Intent.SearchFired -> refresh() + is SearchScreenMviModel.Intent.SetSearch -> setSearch(intent.value) + is SearchScreenMviModel.Intent.SetSubscribedOnly -> applySubscribedOnly(intent.value) + } + } + + private fun setSearch(value: String) { + mvi.updateState { it.copy(searchText = value) } + } + + private fun applySubscribedOnly(value: Boolean) { + mvi.updateState { it.copy(subscribedOnly = value) } + refresh() + } + + private fun refresh() { + currentPage = 1 + mvi.updateState { it.copy(canFetchMore = true, refreshing = true) } + loadNextPage() + } + + private fun loadNextPage() { + val currentState = mvi.uiState.value + if (!currentState.canFetchMore || currentState.loading) { + return + } + + mvi.scope.launch(Dispatchers.IO) { + mvi.updateState { it.copy(loading = true) } + val searchText = mvi.uiState.value.searchText + val auth = identityRepository.authToken.value + val refreshing = currentState.refreshing + val subscribedOnly = currentState.subscribedOnly + if (subscribedOnly) { + val items = communityRepository.getSubscribed( + auth = auth, + ).filter { + it.name.contains(searchText) + } + currentPage++ + mvi.updateState { + val newItems = if (refreshing) { + items + } else { + it.communities + items + } + it.copy( + communities = newItems, + loading = false, + canFetchMore = false, + refreshing = false, + ) + } + } else { + val items = communityRepository.getAll( + query = searchText, + auth = auth, + page = currentPage, + ) + currentPage++ + val canFetchMore = items.size >= PostsRepository.DEFAULT_PAGE_SIZE + mvi.updateState { + val newItems = if (refreshing) { + items + } else { + it.communities + items + } + it.copy( + communities = newItems, + loading = false, + canFetchMore = canFetchMore, + refreshing = false, + ) + } + } + } + } +} diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenMviModel.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenMviModel.kt new file mode 100644 index 000000000..7742541cb --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/viewmodel/SearchScreenMviModel.kt @@ -0,0 +1,28 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel + +import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel + +interface SearchScreenMviModel : + MviModel { + sealed interface Intent { + object Refresh : Intent + object LoadNextPage : Intent + object SearchFired : Intent + data class SetSearch(val value: String) : Intent + data class SetSubscribedOnly(val value: Boolean) : Intent + } + + data class UiState( + val refreshing: Boolean = false, + val loading: Boolean = false, + val canFetchMore: Boolean = true, + val isLogged: Boolean = false, + val instance: String = "", + val searchText: String = "", + val subscribedOnly: Boolean = true, + val communities: List = emptyList(), + ) + + sealed interface Effect +} diff --git a/feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt b/feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt deleted file mode 100644 index b350089a5..000000000 --- a/feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/SearchModule.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.github.diegoberaldin.raccoonforlemmy.feature.search - -import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject -import org.koin.dsl.module - -actual val searchTabModule = module { - factory { - SearchScreenModel( - mvi = DefaultMviModel(SearchScreenMviModel.UiState()), - ) - } -} - -actual fun getSearchScreenModel() = SearchScreenModelHelper.model - -object SearchScreenModelHelper : KoinComponent { - val model: SearchScreenModel by inject() -} diff --git a/feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt b/feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt new file mode 100644 index 000000000..271706fad --- /dev/null +++ b/feature-search/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/di/Utils.kt @@ -0,0 +1,11 @@ +package com.github.diegoberaldin.raccoonforlemmy.feature.search.di + +import com.github.diegoberaldin.raccoonforlemmy.feature.search.viewmodel.SearchScreenModel +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +actual fun getSearchScreenModel() = SearchScreenModelHelper.model + +object SearchScreenModelHelper : KoinComponent { + val model: SearchScreenModel by inject() +} diff --git a/resources/src/commonMain/resources/MR/base/strings.xml b/resources/src/commonMain/resources/MR/base/strings.xml index 3f6b21d60..e32c232a7 100644 --- a/resources/src/commonMain/resources/MR/base/strings.xml +++ b/resources/src/commonMain/resources/MR/base/strings.xml @@ -15,6 +15,7 @@ Missing field Confirm + Search All Local @@ -36,6 +37,9 @@ Top year via %1$s + Search for communities + Subscribed only + You are currently not logged in.\nPlease add an account to continue. diff --git a/resources/src/commonMain/resources/MR/it/strings.xml b/resources/src/commonMain/resources/MR/it/strings.xml index 005da8d2e..42d42c8ab 100644 --- a/resources/src/commonMain/resources/MR/it/strings.xml +++ b/resources/src/commonMain/resources/MR/it/strings.xml @@ -12,6 +12,7 @@ Campo obbligatorio Conferma + Cerca Tutti Locali @@ -33,6 +34,9 @@ Top anno via %1$s + Cerca comunità + Solo sottoscrizioni + Login non effettuato.\nAggiungi un account per continuare. diff --git a/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt b/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt index 6863f520e..227bda2f6 100644 --- a/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt +++ b/shared/src/androidMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt @@ -8,7 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.identity.di.coreIdentityM import com.github.diegoberaldin.raccoonforlemmy.feature.home.di.homeTabModule import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.inboxTabModule import com.github.diegoberaldin.raccoonforlemmy.feature.profile.di.profileTabModule -import com.github.diegoberaldin.raccoonforlemmy.feature.search.searchTabModule +import com.github.diegoberaldin.raccoonforlemmy.feature.search.di.searchTabModule import com.github.diegoberaldin.raccoonforlemmy.feature.settings.di.settingsTabModule import com.github.diegoberaldin.raccoonforlemmy.resources.di.localizationModule import org.koin.dsl.module diff --git a/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt b/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt index 01f8e6bdd..d05b3562c 100644 --- a/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt +++ b/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt @@ -22,7 +22,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.identity.di.getApiConfigu import com.github.diegoberaldin.raccoonforlemmy.feature.home.ui.HomeTab import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.InboxTab import com.github.diegoberaldin.raccoonforlemmy.feature.profile.ui.ProfileTab -import com.github.diegoberaldin.raccoonforlemmy.feature.search.SearchTab +import com.github.diegoberaldin.raccoonforlemmy.feature.search.ui.SearchTab import com.github.diegoberaldin.raccoonforlemmy.feature.settings.ui.SettingsTab import com.github.diegoberaldin.raccoonforlemmy.resources.MR import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository diff --git a/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt b/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt index 513b1a96c..f905179f7 100644 --- a/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt +++ b/shared/src/iosMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/DiHelper.kt @@ -8,7 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.identity.di.coreIdentityM import com.github.diegoberaldin.raccoonforlemmy.feature.home.di.homeTabModule import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.inboxTabModule import com.github.diegoberaldin.raccoonforlemmy.feature.profile.di.profileTabModule -import com.github.diegoberaldin.raccoonforlemmy.feature.search.searchTabModule +import com.github.diegoberaldin.raccoonforlemmy.feature.search.di.searchTabModule import com.github.diegoberaldin.raccoonforlemmy.feature.settings.di.settingsTabModule import com.github.diegoberaldin.raccoonforlemmy.resources.di.localizationModule import org.koin.core.context.startKoin