From 55a15e6b0b0a71203cd1dd1da25ba55df5e54d3c Mon Sep 17 00:00:00 2001 From: Dieguitux Date: Wed, 18 Dec 2024 21:32:20 +0100 Subject: [PATCH] fix: make sure account changes are observed (#172) * rename login screen * update usages of login screen * minor readability changes in login vm/use case * add possibility to observe accounts * update manage accounts view model --- .../repository/DefaultAccountRepositoryTest.kt | 16 ++++++++++++++++ .../persistence/repository/AccountRepository.kt | 3 +++ .../repository/DefaultAccountRepository.kt | 13 +++++++++++++ .../identity/usecase/DefaultLoginUseCase.kt | 2 +- .../feature/profile/main/ProfileMainScreen.kt | 4 ++-- .../profile/notlogged/ProfileNotLoggedScreen.kt | 4 ++-- .../eattrash/raccoonforlemmy/main/MainScreen.kt | 4 ++-- .../unit/drawer/content/ModalDrawerContent.kt | 4 ++-- .../{LoginBottomSheet.kt => LoginScreen.kt} | 2 +- .../raccoonforlemmy/unit/login/LoginViewModel.kt | 2 +- .../manageaccounts/ManageAccountsViewModel.kt | 7 +++++-- 11 files changed, 48 insertions(+), 13 deletions(-) rename unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/{LoginBottomSheet.kt => LoginScreen.kt} (99%) diff --git a/core/persistence/src/androidUnitTest/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepositoryTest.kt b/core/persistence/src/androidUnitTest/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepositoryTest.kt index 6cafed496..262a7894a 100644 --- a/core/persistence/src/androidUnitTest/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepositoryTest.kt +++ b/core/persistence/src/androidUnitTest/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepositoryTest.kt @@ -1,6 +1,7 @@ package com.livefast.eattrash.raccoonforlemmy.core.persistence.repository import app.cash.sqldelight.Query +import app.cash.turbine.test import com.livefast.eattrash.raccoonforlemmy.core.persistence.AccountEntity import com.livefast.eattrash.raccoonforlemmy.core.persistence.AccountsQueries import com.livefast.eattrash.raccoonforlemmy.core.persistence.data.AccountModel @@ -70,6 +71,21 @@ class DefaultAccountRepositoryTest { } } + @Test + fun givenExitingAccounts_whenObserveAll_thenResultIsAsExpected() = + runTest { + val accounts = listOf(createFakeEntity()) + every { query.executeAsList() } returns accounts + + sut.observeAll().test { + val res = awaitItem() + assertTrue(res.size == 1) + } + verify { + queries.getAll() + } + } + @Test fun givenNoActiveAccount_whenGetActive_thenResultIsAsExpected() = runTest { diff --git a/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/AccountRepository.kt b/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/AccountRepository.kt index cabc137f6..04fafa937 100644 --- a/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/AccountRepository.kt +++ b/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/AccountRepository.kt @@ -2,11 +2,14 @@ package com.livefast.eattrash.raccoonforlemmy.core.persistence.repository import androidx.compose.runtime.Stable import com.livefast.eattrash.raccoonforlemmy.core.persistence.data.AccountModel +import kotlinx.coroutines.flow.Flow @Stable interface AccountRepository { suspend fun getAll(): List + fun observeAll(): Flow> + suspend fun getBy( username: String, instance: String, diff --git a/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepository.kt b/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepository.kt index 4e1fbe181..bafae263c 100644 --- a/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepository.kt +++ b/core/persistence/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/core/persistence/repository/DefaultAccountRepository.kt @@ -5,6 +5,11 @@ import com.livefast.eattrash.raccoonforlemmy.core.persistence.data.AccountModel import com.livefast.eattrash.raccoonforlemmy.core.persistence.provider.DatabaseProvider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.channelFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext import org.koin.core.annotation.Single @@ -22,6 +27,14 @@ internal class DefaultAccountRepository( .map { it.toModel() } } + override fun observeAll(): Flow> = + channelFlow { + while (isActive) { + send(getAll()) + delay(1000) + } + }.distinctUntilChanged() + override suspend fun getBy( username: String, instance: String, diff --git a/domain/identity/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt b/domain/identity/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt index acabd89cf..1f2b066d9 100644 --- a/domain/identity/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt +++ b/domain/identity/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/domain/identity/usecase/DefaultLoginUseCase.kt @@ -65,7 +65,7 @@ internal class DefaultLoginUseCase( instance = instance, jwt = auth, ) - val existing = accountRepository.getBy(username, instance) + val existing = accountRepository.getBy(username = username, instance = instance) val accountId = if (existing == null) { // new account with a copy of the anonymous settings diff --git a/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/main/ProfileMainScreen.kt b/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/main/ProfileMainScreen.kt index e5132f190..8968f2d68 100644 --- a/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/main/ProfileMainScreen.kt +++ b/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/main/ProfileMainScreen.kt @@ -64,7 +64,7 @@ import com.livefast.eattrash.raccoonforlemmy.unit.editcommunity.EditCommunityScr import com.livefast.eattrash.raccoonforlemmy.unit.filteredcontents.FilteredContentsScreen import com.livefast.eattrash.raccoonforlemmy.unit.filteredcontents.FilteredContentsType import com.livefast.eattrash.raccoonforlemmy.unit.filteredcontents.toInt -import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginBottomSheet +import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginScreen import com.livefast.eattrash.raccoonforlemmy.unit.manageaccounts.ManageAccountsBottomSheet import com.livefast.eattrash.raccoonforlemmy.unit.managesubscriptions.ManageSubscriptionsScreen import com.livefast.eattrash.raccoonforlemmy.unit.modlog.ModlogScreen @@ -365,7 +365,7 @@ internal object ProfileMainScreen : Tab { onDismiss = { openLogin -> manageAccountsBottomSheetOpened = false if (openLogin) { - navigationCoordinator.pushScreen(LoginBottomSheet()) + navigationCoordinator.pushScreen(LoginScreen()) } }, ) diff --git a/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/notlogged/ProfileNotLoggedScreen.kt b/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/notlogged/ProfileNotLoggedScreen.kt index 77e619057..e12a04e7a 100644 --- a/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/notlogged/ProfileNotLoggedScreen.kt +++ b/feature/profile/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/feature/profile/notlogged/ProfileNotLoggedScreen.kt @@ -20,7 +20,7 @@ import cafe.adriel.voyager.navigator.tab.TabOptions import com.livefast.eattrash.raccoonforlemmy.core.appearance.theme.Spacing import com.livefast.eattrash.raccoonforlemmy.core.l10n.LocalStrings import com.livefast.eattrash.raccoonforlemmy.core.navigation.di.getNavigationCoordinator -import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginBottomSheet +import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginScreen internal object ProfileNotLoggedScreen : Tab { override val options: TabOptions @@ -61,7 +61,7 @@ internal object ProfileNotLoggedScreen : Tab { Button( modifier = Modifier.align(Alignment.CenterHorizontally), onClick = { - navigationCoordinator.pushScreen(LoginBottomSheet()) + navigationCoordinator.pushScreen(LoginScreen()) }, ) { Text(LocalStrings.current.profileButtonLogin) diff --git a/shared/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/main/MainScreen.kt b/shared/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/main/MainScreen.kt index 3e8225ae8..a3bb12bf2 100644 --- a/shared/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/main/MainScreen.kt +++ b/shared/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/main/MainScreen.kt @@ -48,7 +48,7 @@ import com.livefast.eattrash.raccoonforlemmy.feature.home.ui.HomeTab import com.livefast.eattrash.raccoonforlemmy.feature.settings.main.SettingsScreen import com.livefast.eattrash.raccoonforlemmy.navigation.TabNavigationItem import com.livefast.eattrash.raccoonforlemmy.navigation.toTab -import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginBottomSheet +import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginScreen import com.livefast.eattrash.raccoonforlemmy.unit.manageaccounts.ManageAccountsBottomSheet import kotlinx.coroutines.delay import kotlinx.coroutines.flow.drop @@ -317,7 +317,7 @@ internal object MainScreen : Screen { onDismiss = { openLogin -> manageAccountsBottomSheetOpened = false if (openLogin) { - navigationCoordinator.pushScreen(LoginBottomSheet()) + navigationCoordinator.pushScreen(LoginScreen()) } }, ) diff --git a/unit/drawer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/drawer/content/ModalDrawerContent.kt b/unit/drawer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/drawer/content/ModalDrawerContent.kt index bc680c30a..ea21f8cb1 100644 --- a/unit/drawer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/drawer/content/ModalDrawerContent.kt +++ b/unit/drawer/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/drawer/content/ModalDrawerContent.kt @@ -50,7 +50,7 @@ import com.livefast.eattrash.raccoonforlemmy.domain.lemmy.data.toReadableName import com.livefast.eattrash.raccoonforlemmy.unit.drawer.components.DrawerCommunityItem import com.livefast.eattrash.raccoonforlemmy.unit.drawer.components.DrawerHeader import com.livefast.eattrash.raccoonforlemmy.unit.drawer.components.DrawerShortcut -import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginBottomSheet +import com.livefast.eattrash.raccoonforlemmy.unit.login.LoginScreen import com.livefast.eattrash.raccoonforlemmy.unit.manageaccounts.ManageAccountsBottomSheet import com.livefast.eattrash.raccoonforlemmy.unit.selectinstance.SelectInstanceBottomSheet import kotlinx.coroutines.delay @@ -372,7 +372,7 @@ object ModalDrawerContent : Tab { onDismiss = { openLogin -> manageAccountsBottomSheetOpened = false if (openLogin) { - navigationCoordinator.pushScreen(LoginBottomSheet()) + navigationCoordinator.pushScreen(LoginScreen()) } }, ) diff --git a/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginBottomSheet.kt b/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginScreen.kt similarity index 99% rename from unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginBottomSheet.kt rename to unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginScreen.kt index 52b6e0dff..7cd95033b 100644 --- a/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginBottomSheet.kt +++ b/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginScreen.kt @@ -65,7 +65,7 @@ import com.livefast.eattrash.raccoonforlemmy.core.utils.toReadableMessage import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -class LoginBottomSheet : Screen { +class LoginScreen : Screen { companion object { private const val HELP_URL = "https://join-lemmy.org/docs/users/01-getting-started.html" } diff --git a/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginViewModel.kt b/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginViewModel.kt index fd5701714..d8f450b53 100644 --- a/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginViewModel.kt +++ b/unit/login/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/login/LoginViewModel.kt @@ -18,12 +18,12 @@ import org.koin.core.annotation.Factory @Factory(binds = [LoginMviModel::class]) class LoginViewModel( - private val login: LoginUseCase, apiConfigurationRepository: ApiConfigurationRepository, private val identityRepository: IdentityRepository, private val accountRepository: AccountRepository, private val siteRepository: SiteRepository, private val communityRepository: CommunityRepository, + private val login: LoginUseCase, private val notificationCenter: NotificationCenter, ) : DefaultMviModel( initialState = LoginMviModel.UiState(), diff --git a/unit/manageaccounts/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/manageaccounts/ManageAccountsViewModel.kt b/unit/manageaccounts/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/manageaccounts/ManageAccountsViewModel.kt index 05f941f36..b7891012a 100644 --- a/unit/manageaccounts/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/manageaccounts/ManageAccountsViewModel.kt +++ b/unit/manageaccounts/src/commonMain/kotlin/com/livefast/eattrash/raccoonforlemmy/unit/manageaccounts/ManageAccountsViewModel.kt @@ -42,8 +42,11 @@ class ManageAccountsViewModel( } }.launchIn(this) - val accounts = accountRepository.getAll() - updateState { it.copy(accounts = accounts) } + accountRepository + .observeAll() + .onEach { accounts -> + updateState { it.copy(accounts = accounts) } + }.launchIn(this) } } }