From ba7c197957971f71295975fcf2f2614603499534 Mon Sep 17 00:00:00 2001 From: Diego Beraldin Date: Sat, 21 Oct 2023 20:04:38 +0200 Subject: [PATCH] fix: deep link (and hide back button if not possible) --- .../raccoonforlemmy/core/api/di/ApiModule.kt | 2 +- .../api/provider/DefaultServiceProvider.kt | 39 ++-- .../communitydetail/CommunityDetailScreen.kt | 18 +- .../core/commonui/components/UrlUtils.kt | 14 +- .../DefaultNavigationCoordinator.kt | 9 +- .../navigation/NavigationCoordinator.kt | 10 +- .../commonui/postdetail/PostDetailScreen.kt | 21 ++- .../postdetail/PostDetailViewModel.kt | 1 - .../commonui/userdetail/UserDetailScreen.kt | 18 +- .../domain/identity/di/IdentityModule.kt | 7 +- .../repository/ApiConfigurationRepository.kt | 6 +- .../DefaultApiConfigurationRepository.kt | 19 +- .../identity/usecase/DefaultLoginUseCase.kt | 2 +- .../repository/PrivateMessageRepository.kt | 8 +- .../domain/lemmy/repository/SiteRepository.kt | 8 +- .../domain/lemmy/repository/UserRepository.kt | 30 ++-- .../lemmy/repository/di/RepositoryModule.kt | 31 +++- .../feature/search/main/ExploreViewModel.kt | 2 +- .../diegoberaldin/raccoonforlemmy/App.kt | 167 +++++++++--------- .../raccoonforlemmy/MainScreen.kt | 2 +- 20 files changed, 224 insertions(+), 190 deletions(-) diff --git a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/di/ApiModule.kt b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/di/ApiModule.kt index 5e8585b70..70a5814a8 100644 --- a/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/di/ApiModule.kt +++ b/core-api/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/api/di/ApiModule.kt @@ -6,7 +6,7 @@ import org.koin.core.qualifier.named import org.koin.dsl.module val coreApiModule = module { - single { + single(named("default")) { DefaultServiceProvider() } single(named("custom")) { 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 922feee8c..b632ac74e 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 @@ -57,26 +57,6 @@ internal class DefaultServiceProvider : ServiceProvider { private val factory = provideHttpClientEngineFactory() - private val client = HttpClient(factory) { - defaultRequest { - url { - host = currentInstance - } - } - install(HttpTimeout) { - requestTimeoutMillis = 600_000 - connectTimeoutMillis = 30_000 - socketTimeoutMillis = 30_000 - } - install(Logging) { - logger = defaultLogger - level = LogLevel.ALL - } - install(ContentNegotiation) { - json(Json { isLenient = true; ignoreUnknownKeys = true }) - } - } - init { reinitialize() } @@ -87,6 +67,25 @@ internal class DefaultServiceProvider : ServiceProvider { } private fun reinitialize() { + val client = HttpClient(factory) { + defaultRequest { + url { + host = currentInstance + } + } + install(HttpTimeout) { + requestTimeoutMillis = 600_000 + connectTimeoutMillis = 30_000 + socketTimeoutMillis = 30_000 + } + install(Logging) { + logger = defaultLogger + level = LogLevel.ALL + } + install(ContentNegotiation) { + json(Json { isLenient = true; ignoreUnknownKeys = true }) + } + } val ktorfit = Ktorfit.Builder() .baseUrl(baseUrl) .httpClient(client) diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt index dbc60dff2..5da979f61 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/communitydetail/CommunityDetailScreen.kt @@ -213,14 +213,16 @@ class CommunityDetailScreen( ) }, navigationIcon = { - Image( - modifier = Modifier.onClick { - navigator?.pop() - }, - imageVector = Icons.Default.ArrowBack, - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground), - ) + if (navigator?.canPop == true) { + Image( + modifier = Modifier.onClick { + navigator.pop() + }, + imageVector = Icons.Default.ArrowBack, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground), + ) + } }, ) }, floatingActionButton = { diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/UrlUtils.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/UrlUtils.kt index 66ca3971f..a5c09ab60 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/UrlUtils.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/components/UrlUtils.kt @@ -9,7 +9,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel -fun getCommmunityFromUrl(url: String): CommunityModel? { +fun getCommunityFromUrl(url: String?): CommunityModel? { val (normalizedUrl, instance) = normalizeUrl(url) val res = extractCommunity(normalizedUrl) return if (res != null && res.host.isEmpty()) { @@ -19,7 +19,7 @@ fun getCommmunityFromUrl(url: String): CommunityModel? { } } -fun getUserFromUrl(url: String): UserModel? { +fun getUserFromUrl(url: String?): UserModel? { val (normalizedUrl, instance) = normalizeUrl(url) val res = extractUser(normalizedUrl) return if (res != null && res.host.isEmpty()) { @@ -29,10 +29,10 @@ fun getUserFromUrl(url: String): UserModel? { } } -fun getPostFromUrl(url: String): Pair? { +fun getPostFromUrl(url: String?): Pair? { val (normalizedUrl, instance) = normalizeUrl(url) val post = extractPost(normalizedUrl) - return if (post != null && instance != null) { + return if (post != null && instance.isNotEmpty()) { post to instance } else { null @@ -45,7 +45,7 @@ fun handleUrl( uriHandler: UriHandler, navigator: Navigator? = null, ) { - val community = getCommmunityFromUrl(url) + val community = getCommunityFromUrl(url) val user = getUserFromUrl(url) when { @@ -79,8 +79,8 @@ fun handleUrl( } } -private fun normalizeUrl(url: String): Pair { - val matches = Regex("https?://(?.*?)(?/.*)").findAll(url) +private fun normalizeUrl(url: String?): Pair { + val matches = Regex("https?://(?.*?)(?/.*)").findAll(url.orEmpty()) var instance = "" val res = buildString { if (matches.count() > 0) { diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/DefaultNavigationCoordinator.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/DefaultNavigationCoordinator.kt index 884a3d887..0916c0a58 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/DefaultNavigationCoordinator.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/DefaultNavigationCoordinator.kt @@ -7,12 +7,13 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.getAndUpdate import kotlinx.coroutines.launch internal class DefaultNavigationCoordinator : NavigationCoordinator { override val onDoubleTabSelection = MutableSharedFlow() - override val deeplinkUrl = MutableStateFlow(null) + override val deepLinkUrl = MutableStateFlow(null) private var connection: NestedScrollConnection? = null private var navigator: Navigator? = null @@ -43,8 +44,10 @@ internal class DefaultNavigationCoordinator : NavigationCoordinator { } } - override fun submitDeeplink(url: String?) { - deeplinkUrl.value = url + override fun consumeDeeplink(): String? = deepLinkUrl.getAndUpdate { null } + + override fun submitDeeplink(url: String) { + deepLinkUrl.value = url } override fun setCanGoBackCallback(value: (() -> Boolean)?) { diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/NavigationCoordinator.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/NavigationCoordinator.kt index fa598e6f4..b53b5136a 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/NavigationCoordinator.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/navigation/NavigationCoordinator.kt @@ -3,18 +3,20 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.tab.Tab -import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow interface NavigationCoordinator { - val deeplinkUrl: StateFlow - val onDoubleTabSelection: SharedFlow + val onDoubleTabSelection: Flow val inboxUnread: StateFlow + val deepLinkUrl: StateFlow fun setCurrentSection(tab: Tab) - fun submitDeeplink(url: String?) + fun consumeDeeplink(): String? + + fun submitDeeplink(url: String) fun setRootNavigator(value: Navigator?) diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt index 0fb68a458..8d88dcd3d 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailScreen.kt @@ -127,7 +127,8 @@ class PostDetailScreen( model.bindToLifecycle(key) val uiState by model.uiState.collectAsState() val isOnOtherInstance = otherInstance.isNotEmpty() - val navigator = remember { getNavigationCoordinator().getRootNavigator() } + val navigationCoordinator = remember { getNavigationCoordinator() } + val navigator = remember { navigationCoordinator.getRootNavigator() } val bottomSheetNavigator = LocalBottomSheetNavigator.current val topAppBarState = rememberTopAppBarState() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) @@ -207,14 +208,16 @@ class PostDetailScreen( ) }, navigationIcon = { - Image( - modifier = Modifier.onClick { - navigator?.pop() - }, - imageVector = Icons.Default.ArrowBack, - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground), - ) + if (navigator?.canPop == true) { + Image( + modifier = Modifier.onClick { + navigator.pop() + }, + imageVector = Icons.Default.ArrowBack, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground), + ) + } }, ) }, diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailViewModel.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailViewModel.kt index 4f2eacf22..0f3bc84d1 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailViewModel.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/postdetail/PostDetailViewModel.kt @@ -107,7 +107,6 @@ class PostDetailViewModel( } if (highlightCommentId != null) { - val auth = identityRepository.authToken.value val comment = commentRepository.getBy( id = highlightCommentId, auth = auth, diff --git a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt index 2d1d8bfe6..1329396ed 100644 --- a/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt +++ b/core-commonui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/userdetail/UserDetailScreen.kt @@ -192,14 +192,16 @@ class UserDetailScreen( ) }, navigationIcon = { - Image( - modifier = Modifier.onClick { - navigator?.pop() - }, - imageVector = Icons.Default.ArrowBack, - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground), - ) + if (navigator?.canPop == true) { + Image( + modifier = Modifier.onClick { + navigator.pop() + }, + imageVector = Icons.Default.ArrowBack, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground), + ) + } }, ) }, diff --git a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/di/IdentityModule.kt b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/di/IdentityModule.kt index 775e6bd6a..4a4dbc014 100644 --- a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/di/IdentityModule.kt +++ b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/di/IdentityModule.kt @@ -12,12 +12,13 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.DefaultS import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.LoginUseCase import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.LogoutUseCase import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.SwitchAccountUseCase +import org.koin.core.qualifier.named import org.koin.dsl.module val coreIdentityModule = module { single { DefaultApiConfigurationRepository( - serviceProvider = get(), + serviceProvider = get(named("default")), ) } single { @@ -27,7 +28,7 @@ val coreIdentityModule = module { } single { DefaultAuthRepository( - services = get(), + services = get(named("default")), ) } single { @@ -52,7 +53,7 @@ val coreIdentityModule = module { identityRepository = get(), accountRepository = get(), settingsRepository = get(), - serviceProvider = get(), + serviceProvider = get(named("default")), notificationCenter = get(), ) } diff --git a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/ApiConfigurationRepository.kt b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/ApiConfigurationRepository.kt index 1e88aedd0..f44caced4 100644 --- a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/ApiConfigurationRepository.kt +++ b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/ApiConfigurationRepository.kt @@ -1,12 +1,10 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow interface ApiConfigurationRepository { - val instance: Flow - - fun getInstance(): String + val instance: StateFlow fun changeInstance(value: String) } diff --git a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/DefaultApiConfigurationRepository.kt b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/DefaultApiConfigurationRepository.kt index 15c175a1f..49eb58535 100644 --- a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/DefaultApiConfigurationRepository.kt +++ b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/repository/DefaultApiConfigurationRepository.kt @@ -1,25 +1,32 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.isActive internal class DefaultApiConfigurationRepository( private val serviceProvider: ServiceProvider, ) : ApiConfigurationRepository { - override val instance: Flow = channelFlow { + private val scope = CoroutineScope(SupervisorJob()) + + override val instance = channelFlow { while (isActive) { - val value = getInstance() + val value = serviceProvider.currentInstance trySend(value) delay(1000) } - }.distinctUntilChanged() - - override fun getInstance() = serviceProvider.currentInstance + }.distinctUntilChanged().stateIn( + scope = scope, + started = SharingStarted.Lazily, + initialValue = "", + ) override fun changeInstance(value: String) { serviceProvider.changeInstance(value) diff --git a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt index 1ccad4b1c..757a4b5f1 100644 --- a/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt +++ b/domain-identity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt @@ -23,7 +23,7 @@ internal class DefaultLoginUseCase( password: String, totp2faToken: String?, ): Result { - val oldInstance = apiConfigurationRepository.getInstance() + val oldInstance = apiConfigurationRepository.instance.value apiConfigurationRepository.changeInstance(instance) val response = authRepository.login( diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt index bf29dcd3d..e92fb3515 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/PrivateMessageRepository.kt @@ -8,7 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.to import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel class PrivateMessageRepository( - private val serviceProvider: ServiceProvider, + private val services: ServiceProvider, ) { suspend fun getAll( auth: String? = null, @@ -16,7 +16,7 @@ class PrivateMessageRepository( limit: Int = PostRepository.DEFAULT_PAGE_SIZE, unreadOnly: Boolean = true, ): List? = runCatching { - val response = serviceProvider.privateMessages.getPrivateMessages( + val response = services.privateMessages.getPrivateMessages( authHeader = auth.toAuthHeader(), auth = auth, limit = limit, @@ -37,7 +37,7 @@ class PrivateMessageRepository( auth = auth.orEmpty(), recipientId = recipiendId, ) - serviceProvider.privateMessages.createPrivateMessage( + services.privateMessages.createPrivateMessage( authHeader = auth.toAuthHeader(), form = data, ) @@ -53,7 +53,7 @@ class PrivateMessageRepository( auth = auth.orEmpty(), read = read, ) - serviceProvider.privateMessages.markPrivateMessageAsRead( + services.privateMessages.markPrivateMessageAsRead( authHeader = auth.toAuthHeader(), form = data, ) 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 d5e8cd7df..bf5ac531f 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 @@ -9,10 +9,10 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.to import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel class SiteRepository( - private val serviceProvider: ServiceProvider, + private val services: ServiceProvider, ) { suspend fun getCurrentUser(auth: String): UserModel? = runCatching { - val response = serviceProvider.site.get( + val response = services.site.get( auth = auth, authHeader = auth.toAuthHeader(), ) @@ -28,14 +28,14 @@ class SiteRepository( instanceId = id, block = blocked, ) - serviceProvider.site.block( + services.site.block( authHeader = auth.toAuthHeader(), form = data, ) } suspend fun getMetadata(url: String): MetadataModel? = runCatching { - val response = serviceProvider.site.getSiteMetadata( + val response = services.site.getSiteMetadata( url = url, ) response.body()?.metadata?.toModel() 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 3dfe835d3..f06ad8640 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 @@ -16,8 +16,8 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.to import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel class UserRepository( - private val serviceProvider: ServiceProvider, - private val customServiceProvider: ServiceProvider, + private val services: ServiceProvider, + private val customServices: ServiceProvider, ) { suspend fun get( @@ -25,7 +25,7 @@ class UserRepository( auth: String? = null, username: String? = null, ): UserModel? = runCatching { - val response = serviceProvider.user.getDetails( + val response = services.user.getDetails( authHeader = auth.toAuthHeader(), auth = auth, personId = id, @@ -48,8 +48,8 @@ class UserRepository( username: String? = null, auth: String? = null, ): UserModel? = runCatching { - customServiceProvider.changeInstance(instance) - val response = customServiceProvider.user.getDetails( + customServices.changeInstance(instance) + val response = customServices.user.getDetails( authHeader = auth.toAuthHeader(), auth = auth, username = username, @@ -73,7 +73,7 @@ class UserRepository( limit: Int = PostRepository.DEFAULT_PAGE_SIZE, sort: SortType = SortType.Active, ): List? = runCatching { - val response = serviceProvider.user.getDetails( + val response = services.user.getDetails( authHeader = auth.toAuthHeader(), auth = auth, personId = id, @@ -92,7 +92,7 @@ class UserRepository( limit: Int = PostRepository.DEFAULT_PAGE_SIZE, sort: SortType = SortType.Active, ): List? = runCatching { - val response = serviceProvider.user.getDetails( + val response = services.user.getDetails( authHeader = auth.toAuthHeader(), auth = auth, personId = id, @@ -112,7 +112,7 @@ class UserRepository( limit: Int = PostRepository.DEFAULT_PAGE_SIZE, sort: SortType = SortType.Active, ): List? = runCatching { - val response = serviceProvider.user.getDetails( + val response = services.user.getDetails( authHeader = auth.toAuthHeader(), auth = auth, personId = id, @@ -131,7 +131,7 @@ class UserRepository( limit: Int = PostRepository.DEFAULT_PAGE_SIZE, sort: SortType = SortType.Active, ): List? = runCatching { - val response = serviceProvider.user.getDetails( + val response = services.user.getDetails( authHeader = auth.toAuthHeader(), auth = auth, personId = id, @@ -151,7 +151,7 @@ class UserRepository( sort: SortType = SortType.New, unreadOnly: Boolean = true, ): List? = runCatching { - val response = serviceProvider.user.getMentions( + val response = services.user.getMentions( authHeader = auth.toAuthHeader(), auth = auth, limit = limit, @@ -170,7 +170,7 @@ class UserRepository( sort: SortType = SortType.New, unreadOnly: Boolean = true, ): List? = runCatching { - val response = serviceProvider.user.getReplies( + val response = services.user.getReplies( authHeader = auth.toAuthHeader(), auth = auth, limit = limit, @@ -186,7 +186,7 @@ class UserRepository( auth: String? = null, ) { val data = MarkAllAsReadForm(auth.orEmpty()) - serviceProvider.user.markAllAsRead( + services.user.markAllAsRead( authHeader = auth.toAuthHeader(), form = data, ) @@ -198,7 +198,7 @@ class UserRepository( read = read, auth = auth.orEmpty(), ) - serviceProvider.user.markPersonMentionAsRead( + services.user.markPersonMentionAsRead( authHeader = auth.toAuthHeader(), form = data, ) @@ -210,7 +210,7 @@ class UserRepository( read = read, auth = auth.orEmpty(), ) - serviceProvider.user.markCommentReplyAsRead( + services.user.markCommentReplyAsRead( authHeader = auth.toAuthHeader(), form = data, ) @@ -222,7 +222,7 @@ class UserRepository( block = blocked, auth = auth.orEmpty(), ) - serviceProvider.user.block( + services.user.block( authHeader = auth.toAuthHeader(), form = data, ) diff --git a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/di/RepositoryModule.kt b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/di/RepositoryModule.kt index c454b4df8..2ca985547 100644 --- a/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/di/RepositoryModule.kt +++ b/domain-lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/di/RepositoryModule.kt @@ -6,25 +6,42 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepo import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PrivateMessageRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.UserRepository -import org.koin.core.module.dsl.singleOf import org.koin.core.qualifier.named import org.koin.dsl.module val repositoryModule = module { single { PostRepository( - services = get(), + services = get(named("default")), customServices = get(named("custom")), ) } single { CommunityRepository( - services = get(), + services = get(named("default")), customServices = get(named("custom")), ) } - singleOf(::UserRepository) - singleOf(::SiteRepository) - singleOf(::CommentRepository) - singleOf(::PrivateMessageRepository) + single { + UserRepository( + services = get(named("default")), + customServices = get(named("custom")), + ) + } + single { + SiteRepository( + services = get(named("default")), + ) + } + single { + CommentRepository( + services = get(named("default")), + customServices = get(named("custom")), + ) + } + single { + PrivateMessageRepository( + services = get(named("default")), + ) + } } diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/main/ExploreViewModel.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/main/ExploreViewModel.kt index 379d5f571..9cbb5ac1c 100644 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/main/ExploreViewModel.kt +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/main/ExploreViewModel.kt @@ -66,7 +66,7 @@ class ExploreViewModel( mvi.onStarted() mvi.updateState { it.copy( - instance = apiConfigRepository.getInstance(), + instance = apiConfigRepository.instance.value, ) } mvi.scope?.launch(Dispatchers.Main) { 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 39fbea2e3..ef46d9dd1 100644 --- a/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt +++ b/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/App.kt @@ -31,9 +31,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.dp -import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.CurrentScreen -import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator import cafe.adriel.voyager.navigator.tab.TabNavigator @@ -47,7 +45,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.AppTheme import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen -import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getCommmunityFromUrl +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getCommunityFromUrl import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getPostFromUrl import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getUserFromUrl import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator @@ -77,12 +75,20 @@ fun App() { val settingsRepository = remember { getSettingsRepository() } val settings by settingsRepository.currentSettings.collectAsState() var hasBeenInitialized by remember { mutableStateOf(false) } - LaunchedEffect(settingsRepository) { + val apiConfigurationRepository = remember { getApiConfigurationRepository() } + + LaunchedEffect(accountRepository) { val accountId = accountRepository.getActive()?.id val currentSettings = settingsRepository.getSettings(accountId) settingsRepository.changeCurrentSettings(currentSettings) + val lastActiveAccount = accountRepository.getActive() + val lastInstance = lastActiveAccount?.instance + if (lastInstance != null) { + apiConfigurationRepository.changeInstance(lastInstance) + } hasBeenInitialized = true } + val defaultTheme = if (isSystemInDarkTheme()) { UiTheme.Dark.toInt() } else { @@ -100,15 +106,6 @@ fun App() { StringDesc.localeType = StringDesc.LocaleType.Custom(lang) }.launchIn(scope) - val apiConfigurationRepository = remember { getApiConfigurationRepository() } - LaunchedEffect(Unit) { - val lastActiveAccount = accountRepository.getActive() - val lastInstance = lastActiveAccount?.instance - if (lastInstance != null) { - apiConfigurationRepository.changeInstance(lastInstance) - } - } - val themeRepository = remember { getThemeRepository() } LaunchedEffect(settings) { with(themeRepository) { @@ -136,6 +133,73 @@ fun App() { val lang by languageRepository.currentLanguage.collectAsState() LaunchedEffect(lang) {} + val url = navigationCoordinator.consumeDeeplink() + LaunchedEffect(navigationCoordinator, url) { + val community = getCommunityFromUrl(url) + val user = getUserFromUrl(url) + val postAndInstance = getPostFromUrl(url) + val newScreen = when { + community != null -> { + CommunityDetailScreen( + community = community, + otherInstance = community.host, + ) + } + + user != null -> { + UserDetailScreen( + user = user, + otherInstance = user.host, + ) + } + + postAndInstance != null -> { + val (post, otherInstance) = postAndInstance + PostDetailScreen( + post = post, + otherInstance = otherInstance, + ) + } + + else -> null + } + if (newScreen != null) { + navigationCoordinator.getRootNavigator()?.push(newScreen) + } + } + + val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) + val drawerCoordinator = remember { getDrawerCoordinator() } + LaunchedEffect(drawerCoordinator) { + drawerCoordinator.toggleEvents.onEach { evt -> + val navigator = navigationCoordinator.getRootNavigator() + when (evt) { + DrawerEvent.Toggled -> { + drawerState.apply { + if (isClosed) open() else close() + } + } + + is DrawerEvent.OpenCommunity -> { + navigator?.push(CommunityDetailScreen(evt.community)) + } + + is DrawerEvent.OpenMultiCommunity -> { + navigator?.push(MultiCommunityScreen(evt.community)) + } + + DrawerEvent.ManageSubscriptions -> { + navigator?.push(ManageSubscriptionsScreen()) + } + + DrawerEvent.OpenBookmarks -> { + navigator?.push(SavedItemsScreen()) + } + } + }.launchIn(this) + } + val drawerGestureEnabled by drawerCoordinator.gesturesEnabled.collectAsState() + CompositionLocalProvider( LocalDensity provides Density( density = LocalDensity.current.density, @@ -143,73 +207,12 @@ fun App() { ), ) { BottomSheetNavigator( - sheetShape = RoundedCornerShape(topStart = CornerSize.xl, topEnd = CornerSize.xl), + sheetShape = RoundedCornerShape( + topStart = CornerSize.xl, + topEnd = CornerSize.xl + ), sheetBackgroundColor = MaterialTheme.colorScheme.background, ) { - val screens: List = remember(navigationCoordinator.deeplinkUrl) { - val url = navigationCoordinator.deeplinkUrl.value.orEmpty() - val community = getCommmunityFromUrl(url) - val user = getUserFromUrl(url) - val postAndInstance = getPostFromUrl(url) - buildList { - if (community != null) { - add( - CommunityDetailScreen( - community = community, - otherInstance = community.host, - ) - ) - } else if (user != null) { - add( - UserDetailScreen( - user = user, - otherInstance = user.host, - ) - ) - } else if (postAndInstance != null) { - val (post, otherInstance) = postAndInstance - add( - PostDetailScreen( - post = post, - otherInstance = otherInstance, - ) - ) - } else { - add(MainScreen()) - } - } - } - val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) - val drawerCoordinator = remember { getDrawerCoordinator() } - LaunchedEffect(drawerCoordinator) { - drawerCoordinator.toggleEvents.onEach { evt -> - val navigator = navigationCoordinator.getRootNavigator() - when (evt) { - DrawerEvent.Toggled -> { - drawerState.apply { - if (isClosed) open() else close() - } - } - - is DrawerEvent.OpenCommunity -> { - navigator?.push(CommunityDetailScreen(evt.community)) - } - - is DrawerEvent.OpenMultiCommunity -> { - navigator?.push(MultiCommunityScreen(evt.community)) - } - - DrawerEvent.ManageSubscriptions -> { - navigator?.push(ManageSubscriptionsScreen()) - } - - DrawerEvent.OpenBookmarks -> { - navigator?.push(SavedItemsScreen()) - } - } - }.launchIn(this) - } - val drawerGestureEnabled by drawerCoordinator.gesturesEnabled.collectAsState() ModalNavigationDrawer( drawerState = drawerState, gesturesEnabled = drawerGestureEnabled, @@ -217,21 +220,19 @@ fun App() { ModalDrawerSheet { TabNavigator(ModalDrawerContent) } - } + }, ) { Navigator( - screens = screens, + screen = MainScreen, onBackPressed = { val callback = navigationCoordinator.getCanGoBackCallback() callback?.let { it() } ?: true } - ) { - val navigator = LocalNavigator.current + ) { navigator -> navigationCoordinator.setRootNavigator(navigator) if (hasBeenInitialized) { CurrentScreen() } else { - // loading screen Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center, diff --git a/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/MainScreen.kt b/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/MainScreen.kt index 5faae6a41..f194a48e1 100644 --- a/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/MainScreen.kt +++ b/shared/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/MainScreen.kt @@ -43,7 +43,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlin.math.roundToInt -internal class MainScreen : Screen { +internal object MainScreen : Screen { @Composable override fun Content() {