From dd0ca8b9b12dae3bb68d1979b7a147f3e31060a3 Mon Sep 17 00:00:00 2001 From: Yamil Medina Date: Mon, 2 Feb 2026 17:48:42 +0100 Subject: [PATCH 1/4] refactor: implement userprefs dao as replacement of user configs impl - pt1 (WPB-23210) (#3830) * refactor: implement userprefs dao as replacements of user configs impl. * add test * add test --- .../kmmSettings/UserPrefBuilder.kt | 2 +- .../persistence/config/UserConfigStorage.kt | 136 ++++----- .../dao/{unread => }/UserConfigDAO.kt | 6 +- .../kalium/persistence/dao/UserPrefsDAO.kt | 261 ++++++++++++++++ .../dao/{ => unread}/UnreadContentMapper.kt | 6 +- .../persistence/db/UserDatabaseBuilder.kt | 11 +- .../persistence/config/UserConfigDAOTest.kt | 2 +- .../config/UserConfigStorageTest.kt | 9 +- .../dao/UnreadContentMapperTest.kt | 1 + .../persistence/dao/UserPrefsDAOTest.kt | 287 ++++++++++++++++++ .../com/wire/kalium/cells/CellsScope.kt | 2 +- .../kalium/cells/data/CellConfigDataSource.kt | 2 +- .../configuration/UserConfigRepository.kt | 114 ++++--- .../kalium/logic/data/e2ei/E2EIRepository.kt | 4 +- .../kalium/logic/data/team/TeamRepository.kt | 2 +- .../kalium/logic/feature/UserSessionScope.kt | 2 +- .../MarkTeamAppLockStatusAsNotifiedUseCase.kt | 4 +- .../usecase/IsEligibleToStartCallUseCase.kt | 2 +- .../handler/AppLockConfigHandler.kt | 2 +- .../handler/ClassifiedDomainsConfigHandler.kt | 2 +- .../handler/ConferenceCallingConfigHandler.kt | 2 +- .../handler/E2EIConfigHandler.kt | 4 +- .../handler/FileSharingConfigHandler.kt | 5 +- .../handler/GuestRoomConfigHandler.kt | 2 +- ...ondFactorPasswordChallengeConfigHandler.kt | 2 +- .../feature/user/GetDefaultProtocolUseCase.kt | 4 +- .../user/IsFileSharingEnabledUseCase.kt | 4 +- .../user/ObserveE2EIRequiredUseCase.kt | 4 +- ...GuestLinkFeatureFlagAsNotChangedUseCase.kt | 4 +- .../receiver/UserPropertiesEventReceiver.kt | 4 +- ...CertificateRevocationListRepositoryTest.kt | 21 +- .../logic/data/e2ei/E2EIRepositoryTest.kt | 18 +- .../data/e2ei/RevocationListCheckerTest.kt | 2 +- .../properties/UserPropertyRepositoryTest.kt | 22 +- .../logic/data/team/TeamRepositoryTest.kt | 2 +- ...kTeamAppLockStatusAsNotifiedUseCaseTest.kt | 15 +- .../IsEligibleToStartCallUseCaseTest.kt | 17 +- ...erveConferenceCallingEnabledUseCaseTest.kt | 5 +- .../MarkEnablingE2EIAsNotifiedUseCaseTest.kt | 13 +- .../client/ObserveE2EIRequiredUseCaseTest.kt | 15 +- .../client/RegisterMLSClientUseCaseTest.kt | 4 +- .../SyncFeatureConfigsUseCaseTest.kt | 6 +- .../handler/AppLockConfigHandlerTest.kt | 52 ++-- .../ConferenceCallingConfigHandlerTest.kt | 55 ++-- .../mlsmigration/MLSMigrationWorkerTest.kt | 4 +- .../IsFederationSearchAllowedUseCaseTest.kt | 7 +- .../IsFileSharingEnabledUseCaseTest.kt | 18 +- .../user/GetDefaultProtocolUseCaseTest.kt | 16 +- ...tLinkFeatureFlagAsNotChangedUseCaseTest.kt | 25 +- .../FeatureConfigEventReceiverTest.kt | 32 +- .../UserPropertiesEventReceiverTest.kt | 6 +- .../message/ApplicationMessageHandlerTest.kt | 4 +- .../UserConfigRepositoryArrangement.kt | 25 +- .../receiver/asset/AssetMessageHandlerTest.kt | 6 +- 54 files changed, 915 insertions(+), 367 deletions(-) rename data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/{unread => }/UserConfigDAO.kt (98%) create mode 100644 data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt rename data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/{ => unread}/UnreadContentMapper.kt (89%) create mode 100644 data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAOTest.kt diff --git a/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt index ba66be6f495..2adbf3aac22 100644 --- a/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ b/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt @@ -24,7 +24,7 @@ import com.wire.kalium.persistence.config.UserConfigStorage import com.wire.kalium.persistence.config.UserConfigStorageImpl import com.wire.kalium.persistence.dao.UserIDEntity -actual class UserPrefBuilder( +actual class UserPrefBuilder constructor( userId: UserIDEntity, rootPath: String, shouldEncryptData: Boolean = true diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt index 202b4d190c5..6d1693553da 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt @@ -38,7 +38,7 @@ interface UserConfigStorage { /** * save flag from the user settings to enforce and disable App Lock */ - fun persistAppLockStatus( + suspend fun persistAppLockStatus( isEnforced: Boolean, inactivityTimeoutSecs: Second, isStatusChanged: Boolean? @@ -47,42 +47,42 @@ interface UserConfigStorage { /** * get the saved flag to know if App Lock is enforced or not */ - fun appLockStatus(): AppLockConfigEntity? + suspend fun appLockStatus(): AppLockConfigEntity? /** * returns a Flow of the saved App Lock status */ fun appLockFlow(): Flow - fun setTeamAppLockAsNotified() + suspend fun setTeamAppLockAsNotified() /** * Save flag from the file sharing api, and if the status changes */ - fun persistFileSharingStatus(status: Boolean, isStatusChanged: Boolean?) + suspend fun persistFileSharingStatus(status: Boolean, isStatusChanged: Boolean?) /** * Get the saved flag that been saved to know if the file sharing is enabled or not with the flag * to know if there was a status change */ - fun isFileSharingEnabled(): IsFileSharingEnabledEntity? + suspend fun isFileSharingEnabled(): IsFileSharingEnabledEntity? /** * Returns the Flow of file sharing status */ fun isFileSharingEnabledFlow(): Flow - fun setFileSharingAsNotified() + suspend fun setFileSharingAsNotified() /** * Returns a Flow containing the status and list of classified domains */ - fun isClassifiedDomainsEnabledFlow(): Flow + fun isClassifiedDomainsEnabledFlow(): Flow /** *Save the flag and list of trusted domains */ - fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) + suspend fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) /** * Saves the flag that indicates whether a 2FA challenge is @@ -90,7 +90,7 @@ interface UserConfigStorage { * Login, Create Account, Register Client, etc. * @see isSecondFactorPasswordChallengeRequired */ - fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) + suspend fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) /** * Checks if the 2FA challenge is @@ -98,37 +98,37 @@ interface UserConfigStorage { * Login, Create Account, Register Client, etc. * @see persistSecondFactorPasswordChallengeStatus */ - fun isSecondFactorPasswordChallengeRequired(): Boolean + suspend fun isSecondFactorPasswordChallengeRequired(): Boolean /** * Save default protocol to use */ - fun persistDefaultProtocol(protocol: SupportedProtocolEntity) + suspend fun persistDefaultProtocol(protocol: SupportedProtocolEntity) /** * Gets default protocol to use. Defaults to PROTEUS if not default protocol has been saved. */ - fun defaultProtocol(): SupportedProtocolEntity + suspend fun defaultProtocol(): SupportedProtocolEntity /** * Save flag from the user settings to enable and disable MLS */ - fun enableMLS(enabled: Boolean) + suspend fun enableMLS(enabled: Boolean) /** * Get the saved flag to know if MLS enabled or not */ - fun isMLSEnabled(): Boolean + suspend fun isMLSEnabled(): Boolean /** * Save MLSE2EISetting */ - fun setE2EISettings(settingEntity: E2EISettingsEntity?) + suspend fun setE2EISettings(settingEntity: E2EISettingsEntity?) /** * Get MLSE2EISetting */ - fun getE2EISettings(): E2EISettingsEntity? + suspend fun getE2EISettings(): E2EISettingsEntity? /** * Get Flow of the saved MLSE2EISetting @@ -138,51 +138,51 @@ interface UserConfigStorage { /** * Save flag from user settings to enable or disable Conference Calling */ - fun persistConferenceCalling(enabled: Boolean) + suspend fun persistConferenceCalling(enabled: Boolean) /** * Get the saved flag to know if Conference Calling is enabled or not */ - fun isConferenceCallingEnabled(): Boolean + suspend fun isConferenceCallingEnabled(): Boolean /** * Get a flow of saved flag to know if conference calling is enabled or not */ - fun isConferenceCallingEnabledFlow(): Flow + suspend fun isConferenceCallingEnabledFlow(): Flow - fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) + suspend fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) - fun shouldUseSftForOneOnOneCalls(): Boolean + suspend fun shouldUseSftForOneOnOneCalls(): Boolean /** * Get the saved flag to know whether user's Read Receipts are currently enabled or not */ - fun areReadReceiptsEnabled(): Flow + suspend fun areReadReceiptsEnabled(): Flow /** * Persist the flag to indicate if user's Read Receipts are enabled or not. */ - fun persistReadReceipts(enabled: Boolean) + suspend fun persistReadReceipts(enabled: Boolean) /** * Get the saved global flag to know whether user's typing indicator is currently enabled or not. */ - fun isTypingIndicatorEnabled(): Flow + suspend fun isTypingIndicatorEnabled(): Flow /** * Persist the flag to indicate whether user's typing indicator global flag is enabled or not. */ - fun persistTypingIndicator(enabled: Boolean) + suspend fun persistTypingIndicator(enabled: Boolean) - fun persistGuestRoomLinkFeatureFlag(status: Boolean, isStatusChanged: Boolean?) - fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? + suspend fun persistGuestRoomLinkFeatureFlag(status: Boolean, isStatusChanged: Boolean?) + suspend fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? fun isGuestRoomLinkEnabledFlow(): Flow - fun isScreenshotCensoringEnabledFlow(): Flow - fun persistScreenshotCensoring(enabled: Boolean) - fun setIfAbsentE2EINotificationTime(timeStamp: Long) - fun getE2EINotificationTime(): Long? - fun e2EINotificationTimeFlow(): Flow - fun updateE2EINotificationTime(timeStamp: Long) + suspend fun isScreenshotCensoringEnabledFlow(): Flow + suspend fun persistScreenshotCensoring(enabled: Boolean) + suspend fun setIfAbsentE2EINotificationTime(timeStamp: Long) + suspend fun getE2EINotificationTime(): Long? + suspend fun e2EINotificationTimeFlow(): Flow + suspend fun updateE2EINotificationTime(timeStamp: Long) } @Serializable @@ -279,7 +279,7 @@ data class WireCellsConfigEntity( ) @Suppress("TooManyFunctions") -class UserConfigStorageImpl( +class UserConfigStorageImpl constructor( private val kaliumPreferences: KaliumPreferences ) : UserConfigStorage { @@ -349,7 +349,7 @@ class UserConfigStorageImpl( onBufferOverflow = BufferOverflow.DROP_OLDEST ) - override fun persistAppLockStatus( + override suspend fun persistAppLockStatus( isEnforced: Boolean, inactivityTimeoutSecs: Second, isStatusChanged: Boolean? @@ -363,7 +363,7 @@ class UserConfigStorageImpl( } } - override fun setTeamAppLockAsNotified() { + override suspend fun setTeamAppLockAsNotified() { val newValue = kaliumPreferences.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) ?.copy(isStatusChanged = false) @@ -377,7 +377,7 @@ class UserConfigStorageImpl( } } - override fun appLockStatus(): AppLockConfigEntity? = + override suspend fun appLockStatus(): AppLockConfigEntity? = kaliumPreferences.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) override fun appLockFlow(): Flow = appLockFlow.map { @@ -386,7 +386,7 @@ class UserConfigStorageImpl( emit(appLockStatus()) } - override fun persistFileSharingStatus( + override suspend fun persistFileSharingStatus( status: Boolean, isStatusChanged: Boolean? ) { @@ -399,7 +399,7 @@ class UserConfigStorageImpl( } } - override fun isFileSharingEnabled(): IsFileSharingEnabledEntity? = + override suspend fun isFileSharingEnabled(): IsFileSharingEnabledEntity? = kaliumPreferences.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) override fun isFileSharingEnabledFlow(): Flow = @@ -408,7 +408,7 @@ class UserConfigStorageImpl( .onStart { emit(isFileSharingEnabled()) } .distinctUntilChanged() - override fun setFileSharingAsNotified() { + override suspend fun setFileSharingAsNotified() { val newValue = kaliumPreferences.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) ?.copy(isStatusChanged = false) @@ -422,7 +422,7 @@ class UserConfigStorageImpl( } } - override fun isClassifiedDomainsEnabledFlow(): Flow { + override fun isClassifiedDomainsEnabledFlow(): Flow { return isClassifiedDomainsEnabledFlow .map { kaliumPreferences.getSerializable( @@ -439,7 +439,7 @@ class UserConfigStorageImpl( }.distinctUntilChanged() } - override fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) { + override suspend fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) { kaliumPreferences.putSerializable( ENABLE_CLASSIFIED_DOMAINS, ClassifiedDomainsEntity(status, classifiedDomains), @@ -449,28 +449,28 @@ class UserConfigStorageImpl( } } - override fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) { + override suspend fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) { kaliumPreferences.putBoolean(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE, isRequired) } - override fun isSecondFactorPasswordChallengeRequired(): Boolean = + override suspend fun isSecondFactorPasswordChallengeRequired(): Boolean = kaliumPreferences.getBoolean(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE, false) - override fun persistDefaultProtocol(protocol: SupportedProtocolEntity) { + override suspend fun persistDefaultProtocol(protocol: SupportedProtocolEntity) { kaliumPreferences.putString(DEFAULT_PROTOCOL, protocol.name) } - override fun defaultProtocol(): SupportedProtocolEntity = + override suspend fun defaultProtocol(): SupportedProtocolEntity = kaliumPreferences.getString(DEFAULT_PROTOCOL)?.let { SupportedProtocolEntity.valueOf(it) } ?: SupportedProtocolEntity.PROTEUS - override fun enableMLS(enabled: Boolean) { + override suspend fun enableMLS(enabled: Boolean) { kaliumPreferences.putBoolean(ENABLE_MLS, enabled) } - override fun isMLSEnabled(): Boolean = kaliumPreferences.getBoolean(ENABLE_MLS, false) + override suspend fun isMLSEnabled(): Boolean = kaliumPreferences.getBoolean(ENABLE_MLS, false) - override fun setE2EISettings(settingEntity: E2EISettingsEntity?) { + override suspend fun setE2EISettings(settingEntity: E2EISettingsEntity?) { if (settingEntity == null) { kaliumPreferences.remove(E2EI_SETTINGS) } else { @@ -484,7 +484,7 @@ class UserConfigStorageImpl( } } - override fun getE2EISettings(): E2EISettingsEntity? { + override suspend fun getE2EISettings(): E2EISettingsEntity? { return kaliumPreferences.getSerializable(E2EI_SETTINGS, E2EISettingsEntity.serializer()) } @@ -493,74 +493,74 @@ class UserConfigStorageImpl( .onStart { emit(getE2EISettings()) } .distinctUntilChanged() - override fun setIfAbsentE2EINotificationTime(timeStamp: Long) { + override suspend fun setIfAbsentE2EINotificationTime(timeStamp: Long) { getE2EINotificationTime().let { current -> if (current == null || current <= 0) kaliumPreferences.putLong(E2EI_NOTIFICATION_TIME, timeStamp).also { e2EINotificationFlow.tryEmit(Unit) } } } - override fun updateE2EINotificationTime(timeStamp: Long) { + override suspend fun updateE2EINotificationTime(timeStamp: Long) { kaliumPreferences.putLong(E2EI_NOTIFICATION_TIME, timeStamp).also { e2EINotificationFlow.tryEmit(Unit) } } - override fun getE2EINotificationTime(): Long? { + override suspend fun getE2EINotificationTime(): Long? { return kaliumPreferences.getLong(E2EI_NOTIFICATION_TIME) } - override fun e2EINotificationTimeFlow(): Flow = e2EINotificationFlow + override suspend fun e2EINotificationTimeFlow(): Flow = e2EINotificationFlow .map { getE2EINotificationTime() } .onStart { emit(getE2EINotificationTime()) } .distinctUntilChanged() - override fun persistConferenceCalling(enabled: Boolean) { + override suspend fun persistConferenceCalling(enabled: Boolean) { kaliumPreferences.putBoolean(ENABLE_CONFERENCE_CALLING, enabled) conferenceCallingEnabledFlow.tryEmit(Unit) } - override fun isConferenceCallingEnabled(): Boolean = + override suspend fun isConferenceCallingEnabled(): Boolean = kaliumPreferences.getBoolean( ENABLE_CONFERENCE_CALLING, DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE ) - override fun isConferenceCallingEnabledFlow(): Flow = conferenceCallingEnabledFlow + override suspend fun isConferenceCallingEnabledFlow(): Flow = conferenceCallingEnabledFlow .map { isConferenceCallingEnabled() } .onStart { emit(isConferenceCallingEnabled()) } - override fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) { + override suspend fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) { kaliumPreferences.putBoolean(USE_SFT_FOR_ONE_ON_ONE_CALLS, shouldUse) } - override fun shouldUseSftForOneOnOneCalls(): Boolean = + override suspend fun shouldUseSftForOneOnOneCalls(): Boolean = kaliumPreferences.getBoolean( USE_SFT_FOR_ONE_ON_ONE_CALLS, DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE ) - override fun areReadReceiptsEnabled(): Flow = areReadReceiptsEnabledFlow + override suspend fun areReadReceiptsEnabled(): Flow = areReadReceiptsEnabledFlow .map { kaliumPreferences.getBoolean(ENABLE_READ_RECEIPTS, true) } .onStart { emit(kaliumPreferences.getBoolean(ENABLE_READ_RECEIPTS, true)) } .distinctUntilChanged() - override fun persistReadReceipts(enabled: Boolean) { + override suspend fun persistReadReceipts(enabled: Boolean) { kaliumPreferences.putBoolean(ENABLE_READ_RECEIPTS, enabled).also { areReadReceiptsEnabledFlow.tryEmit(Unit) } } - override fun isTypingIndicatorEnabled(): Flow = isTypingIndicatorEnabledFlow + override suspend fun isTypingIndicatorEnabled(): Flow = isTypingIndicatorEnabledFlow .map { kaliumPreferences.getBoolean(ENABLE_TYPING_INDICATOR, true) } .onStart { emit(kaliumPreferences.getBoolean(ENABLE_TYPING_INDICATOR, true)) } .distinctUntilChanged() - override fun persistTypingIndicator(enabled: Boolean) { + override suspend fun persistTypingIndicator(enabled: Boolean) { kaliumPreferences.putBoolean(ENABLE_TYPING_INDICATOR, enabled).also { isTypingIndicatorEnabledFlow.tryEmit(Unit) } } - override fun persistGuestRoomLinkFeatureFlag( + override suspend fun persistGuestRoomLinkFeatureFlag( status: Boolean, isStatusChanged: Boolean? ) { @@ -573,7 +573,7 @@ class UserConfigStorageImpl( } } - override fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? = + override suspend fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? = kaliumPreferences.getSerializable( GUEST_ROOM_LINK, IsGuestRoomLinkEnabledEntity.serializer() @@ -585,19 +585,19 @@ class UserConfigStorageImpl( .onStart { emit(isGuestRoomLinkEnabled()) } .distinctUntilChanged() - override fun isScreenshotCensoringEnabledFlow(): Flow = + override suspend fun isScreenshotCensoringEnabledFlow(): Flow = isScreenshotCensoringEnabledFlow .map { kaliumPreferences.getBoolean(ENABLE_SCREENSHOT_CENSORING, false) } .onStart { emit(kaliumPreferences.getBoolean(ENABLE_SCREENSHOT_CENSORING, false)) } .distinctUntilChanged() - override fun persistScreenshotCensoring(enabled: Boolean) { + override suspend fun persistScreenshotCensoring(enabled: Boolean) { kaliumPreferences.putBoolean(ENABLE_SCREENSHOT_CENSORING, enabled).also { isScreenshotCensoringEnabledFlow.tryEmit(Unit) } } - private companion object { + companion object { const val FILE_SHARING = "file_sharing" const val GUEST_ROOM_LINK = "guest_room_link" const val ENABLE_CLASSIFIED_DOMAINS = "enable_classified_domains" diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UserConfigDAO.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserConfigDAO.kt similarity index 98% rename from data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UserConfigDAO.kt rename to data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserConfigDAO.kt index d789b1e361f..d5a5a003e6c 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UserConfigDAO.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserConfigDAO.kt @@ -1,6 +1,6 @@ /* * Wire - * Copyright (C) 2024 Wire Swiss GmbH + * Copyright (C) 2026 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,15 +18,13 @@ @file:Suppress("TooManyFunctions") -package com.wire.kalium.persistence.dao.unread +package com.wire.kalium.persistence.dao import com.wire.kalium.persistence.config.LastPreKey import com.wire.kalium.persistence.config.LegalHoldRequestEntity import com.wire.kalium.persistence.config.MLSMigrationEntity import com.wire.kalium.persistence.config.TeamSettingsSelfDeletionStatusEntity import com.wire.kalium.persistence.config.WireCellsConfigEntity -import com.wire.kalium.persistence.dao.MetadataDAO -import com.wire.kalium.persistence.dao.SupportedProtocolEntity import com.wire.kalium.persistence.model.SupportedCipherSuiteEntity import io.mockative.Mockable import kotlinx.coroutines.flow.Flow diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt new file mode 100644 index 00000000000..eefeb091ae8 --- /dev/null +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt @@ -0,0 +1,261 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.persistence.dao + +import com.wire.kalium.persistence.config.AppLockConfigEntity +import com.wire.kalium.persistence.config.ClassifiedDomainsEntity +import com.wire.kalium.persistence.config.E2EISettingsEntity +import com.wire.kalium.persistence.config.IsFileSharingEnabledEntity +import com.wire.kalium.persistence.config.IsGuestRoomLinkEnabledEntity +import com.wire.kalium.persistence.config.UserConfigStorage +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.APP_LOCK +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.DEFAULT_PROTOCOL +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.E2EI_NOTIFICATION_TIME +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.E2EI_SETTINGS +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_CLASSIFIED_DOMAINS +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_CONFERENCE_CALLING +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_MLS +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_READ_RECEIPTS +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_SCREENSHOT_CENSORING +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_TYPING_INDICATOR +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.FILE_SHARING +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.GUEST_ROOM_LINK +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE +import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.USE_SFT_FOR_ONE_ON_ONE_CALLS +import com.wire.kalium.util.time.Second +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +@Suppress("TooManyFunctions") +internal class UserPrefsDAO( + private val metadataDAO: MetadataDAO, +) : UserConfigStorage { + override suspend fun persistAppLockStatus( + isEnforced: Boolean, + inactivityTimeoutSecs: Second, + isStatusChanged: Boolean? + ) { + metadataDAO.putSerializable( + APP_LOCK, + AppLockConfigEntity(inactivityTimeoutSecs, isEnforced, isStatusChanged), + AppLockConfigEntity.serializer(), + ) + } + + override suspend fun appLockStatus(): AppLockConfigEntity? { + return metadataDAO.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + } + + override fun appLockFlow(): Flow { + return metadataDAO.observeSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + } + + override suspend fun setTeamAppLockAsNotified() { + val newValue = + metadataDAO.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + ?.copy(isStatusChanged = false) + ?: return + metadataDAO.putSerializable( + APP_LOCK, + newValue, + AppLockConfigEntity.serializer() + ) + } + + override suspend fun persistFileSharingStatus(status: Boolean, isStatusChanged: Boolean?) { + metadataDAO.putSerializable( + FILE_SHARING, + IsFileSharingEnabledEntity(status, isStatusChanged), + IsFileSharingEnabledEntity.serializer() + ) + } + + override suspend fun isFileSharingEnabled(): IsFileSharingEnabledEntity? { + return metadataDAO.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + } + + override fun isFileSharingEnabledFlow(): Flow { + return metadataDAO.observeSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + } + + override suspend fun setFileSharingAsNotified() { + val newValue = + metadataDAO.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + ?.copy(isStatusChanged = false) + ?: return + metadataDAO.putSerializable( + FILE_SHARING, + newValue, + IsFileSharingEnabledEntity.serializer() + ) + } + + override fun isClassifiedDomainsEnabledFlow(): Flow { + return metadataDAO.observeSerializable(ENABLE_CLASSIFIED_DOMAINS, ClassifiedDomainsEntity.serializer()) + } + + override suspend fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) { + metadataDAO.putSerializable( + ENABLE_CLASSIFIED_DOMAINS, + ClassifiedDomainsEntity(status, classifiedDomains), + ClassifiedDomainsEntity.serializer() + ) + } + + override suspend fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) { + metadataDAO.insertValue(value = isRequired.toString(), key = REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE) + } + + override suspend fun isSecondFactorPasswordChallengeRequired(): Boolean { + return metadataDAO.valueByKey(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE)?.toBoolean() ?: false + } + + override suspend fun persistDefaultProtocol(protocol: SupportedProtocolEntity) { + metadataDAO.insertValue(value = protocol.name, key = DEFAULT_PROTOCOL) + } + + override suspend fun defaultProtocol(): SupportedProtocolEntity { + return metadataDAO.valueByKey(DEFAULT_PROTOCOL)?.let { SupportedProtocolEntity.valueOf(it) } + ?: SupportedProtocolEntity.PROTEUS + } + + override suspend fun enableMLS(enabled: Boolean) { + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_MLS) + } + + override suspend fun isMLSEnabled(): Boolean { + return metadataDAO.valueByKey(ENABLE_MLS)?.toBoolean() ?: false + } + + override suspend fun setE2EISettings(settingEntity: E2EISettingsEntity?) { + if (settingEntity == null) { + metadataDAO.deleteValue(E2EI_SETTINGS) + } else { + metadataDAO.putSerializable( + E2EI_SETTINGS, + settingEntity, + E2EISettingsEntity.serializer() + ) + } + } + + override suspend fun getE2EISettings(): E2EISettingsEntity? { + return metadataDAO.getSerializable(E2EI_SETTINGS, E2EISettingsEntity.serializer()) + } + + override fun e2EISettingsFlow(): Flow { + return metadataDAO.observeSerializable(E2EI_SETTINGS, E2EISettingsEntity.serializer()) + } + + override suspend fun persistConferenceCalling(enabled: Boolean) { + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_CONFERENCE_CALLING) + } + + override suspend fun isConferenceCallingEnabled(): Boolean { + return metadataDAO.valueByKey(ENABLE_CONFERENCE_CALLING)?.toBoolean() ?: DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE + } + + override suspend fun isConferenceCallingEnabledFlow(): Flow { + return metadataDAO.valueByKeyFlow(ENABLE_CONFERENCE_CALLING).map { value -> + value?.toBoolean() ?: DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE + } + } + + override suspend fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) { + metadataDAO.insertValue(value = shouldUse.toString(), key = USE_SFT_FOR_ONE_ON_ONE_CALLS) + } + + override suspend fun shouldUseSftForOneOnOneCalls(): Boolean { + return metadataDAO.valueByKey(USE_SFT_FOR_ONE_ON_ONE_CALLS)?.toBoolean() ?: DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE + } + + override suspend fun areReadReceiptsEnabled(): Flow { + return metadataDAO.valueByKeyFlow(ENABLE_READ_RECEIPTS).map { + it?.toBoolean() ?: true + } + } + + override suspend fun persistReadReceipts(enabled: Boolean) { + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_READ_RECEIPTS) + } + + override suspend fun isTypingIndicatorEnabled(): Flow { + return metadataDAO.valueByKeyFlow(ENABLE_TYPING_INDICATOR).map { + it?.toBoolean() ?: true + } + } + + override suspend fun persistTypingIndicator(enabled: Boolean) { + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_TYPING_INDICATOR) + } + + override suspend fun persistGuestRoomLinkFeatureFlag(status: Boolean, isStatusChanged: Boolean?) { + metadataDAO.putSerializable( + GUEST_ROOM_LINK, + IsGuestRoomLinkEnabledEntity(status, isStatusChanged), + IsGuestRoomLinkEnabledEntity.serializer() + ) + } + + override suspend fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? { + return metadataDAO.getSerializable( + GUEST_ROOM_LINK, + IsGuestRoomLinkEnabledEntity.serializer() + ) + } + + override fun isGuestRoomLinkEnabledFlow(): Flow { + return metadataDAO.observeSerializable( + GUEST_ROOM_LINK, + IsGuestRoomLinkEnabledEntity.serializer() + ) + } + + override suspend fun isScreenshotCensoringEnabledFlow(): Flow { + return metadataDAO.valueByKeyFlow(ENABLE_SCREENSHOT_CENSORING).map { + it?.toBoolean() ?: false + } + } + + override suspend fun persistScreenshotCensoring(enabled: Boolean) { + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_SCREENSHOT_CENSORING) + } + + override suspend fun setIfAbsentE2EINotificationTime(timeStamp: Long) { + getE2EINotificationTime().let { current -> + if (current == null || current <= 0) + metadataDAO.insertValue(value = timeStamp.toString(), key = E2EI_NOTIFICATION_TIME) + } + } + + override suspend fun getE2EINotificationTime(): Long? { + return metadataDAO.valueByKey(E2EI_NOTIFICATION_TIME)?.toLong() + } + + override suspend fun e2EINotificationTimeFlow(): Flow { + return metadataDAO.valueByKeyFlow(E2EI_NOTIFICATION_TIME).map { + it?.toLong() + } + } + + override suspend fun updateE2EINotificationTime(timeStamp: Long) { + metadataDAO.insertValue(value = timeStamp.toString(), key = E2EI_NOTIFICATION_TIME) + } +} diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UnreadContentMapper.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UnreadContentMapper.kt similarity index 89% rename from data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UnreadContentMapper.kt rename to data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UnreadContentMapper.kt index 7a10829747e..933e988ec22 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UnreadContentMapper.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UnreadContentMapper.kt @@ -1,6 +1,6 @@ /* * Wire - * Copyright (C) 2024 Wire Swiss GmbH + * Copyright (C) 2026 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,12 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ - -package com.wire.kalium.persistence.dao +package com.wire.kalium.persistence.dao.unread import com.wire.kalium.persistence.dao.message.UnreadContentCountEntity import com.wire.kalium.persistence.util.JsonSerializer -import kotlinx.serialization.decodeFromString object UnreadContentMapper { diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt index a23ba3fd155..670f47a4822 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt @@ -29,6 +29,7 @@ import com.wire.kalium.persistence.backup.DatabaseImporter import com.wire.kalium.persistence.backup.DatabaseImporterImpl import com.wire.kalium.persistence.backup.ObfuscatedCopyExporter import com.wire.kalium.persistence.cache.FlowCache +import com.wire.kalium.persistence.config.UserConfigStorage import com.wire.kalium.persistence.dao.ConnectionDAO import com.wire.kalium.persistence.dao.ConnectionDAOImpl import com.wire.kalium.persistence.dao.ConversationIDEntity @@ -42,10 +43,13 @@ import com.wire.kalium.persistence.dao.ServiceDAO import com.wire.kalium.persistence.dao.ServiceDAOImpl import com.wire.kalium.persistence.dao.TeamDAO import com.wire.kalium.persistence.dao.TeamDAOImpl +import com.wire.kalium.persistence.dao.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAOImpl import com.wire.kalium.persistence.dao.UserDAO import com.wire.kalium.persistence.dao.UserDAOImpl import com.wire.kalium.persistence.dao.UserDetailsEntity import com.wire.kalium.persistence.dao.UserIDEntity +import com.wire.kalium.persistence.dao.UserPrefsDAO import com.wire.kalium.persistence.dao.asset.AssetDAO import com.wire.kalium.persistence.dao.asset.AssetDAOImpl import com.wire.kalium.persistence.dao.call.CallDAO @@ -84,8 +88,6 @@ import com.wire.kalium.persistence.dao.reaction.ReactionDAO import com.wire.kalium.persistence.dao.reaction.ReactionDAOImpl import com.wire.kalium.persistence.dao.receipt.ReceiptDAO import com.wire.kalium.persistence.dao.receipt.ReceiptDAOImpl -import com.wire.kalium.persistence.dao.unread.UserConfigDAO -import com.wire.kalium.persistence.dao.unread.UserConfigDAOImpl import com.wire.kalium.persistence.db.feeders.MentionsFeeder import com.wire.kalium.persistence.db.feeders.MessagesFeeder import com.wire.kalium.persistence.db.feeders.ReactionsFeeder @@ -204,8 +206,9 @@ class UserDatabaseBuilder internal constructor( val messageMetaDataDAO: MessageMetadataDAO get() = MessageMetadataDAOImpl(database.messageMetadataQueries, readDispatcher) - val userConfigDAO: UserConfigDAO - get() = UserConfigDAOImpl(metadataDAO) + val userConfigDAO: UserConfigDAO by lazy { UserConfigDAOImpl(metadataDAO) } + + val userPrefsDAO: UserConfigStorage by lazy { UserPrefsDAO(metadataDAO) } val connectionDAO: ConnectionDAO get() = ConnectionDAOImpl( diff --git a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigDAOTest.kt b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigDAOTest.kt index a1902160ce8..a5c48afde44 100644 --- a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigDAOTest.kt +++ b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigDAOTest.kt @@ -20,7 +20,7 @@ package com.wire.kalium.persistence.config import app.cash.turbine.test import com.wire.kalium.persistence.BaseDatabaseTest import com.wire.kalium.persistence.dao.UserIDEntity -import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAO import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest diff --git a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigStorageTest.kt b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigStorageTest.kt index b1ddab9af78..d895ddbec6b 100644 --- a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigStorageTest.kt +++ b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/config/UserConfigStorageTest.kt @@ -24,7 +24,6 @@ import com.russhwolf.settings.Settings import com.wire.kalium.persistence.dao.SupportedProtocolEntity import com.wire.kalium.persistence.kmmSettings.KaliumPreferences import com.wire.kalium.persistence.kmmSettings.KaliumPreferencesSettings -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import kotlin.test.AfterTest @@ -115,7 +114,7 @@ class UserConfigStorageTest { } @Test - fun givenGuestRoomLinkStatusIsSetToFalse_whenGettingItsValue_thenItShouldBeFalse() { + fun givenGuestRoomLinkStatusIsSetToFalse_whenGettingItsValue_thenItShouldBeFalse() = runTest { userConfigStorage.persistGuestRoomLinkFeatureFlag(status = false, isStatusChanged = false) userConfigStorage.isGuestRoomLinkEnabled()?.status?.let { assertFalse { it } @@ -123,7 +122,7 @@ class UserConfigStorageTest { } @Test - fun givenGuestRoomLinkStatusIsSetToTrue_whenGettingItsValue_thenItShouldBeTrue() { + fun givenGuestRoomLinkStatusIsSetToTrue_whenGettingItsValue_thenItShouldBeTrue() = runTest { userConfigStorage.persistGuestRoomLinkFeatureFlag(status = true, isStatusChanged = false) userConfigStorage.isGuestRoomLinkEnabled()?.status?.let { assertTrue { it } @@ -195,12 +194,12 @@ class UserConfigStorageTest { } @Test - fun givenDefaultProtocolIsNotSet_whenGettingItsValue_thenItShouldBeProteus() { + fun givenDefaultProtocolIsNotSet_whenGettingItsValue_thenItShouldBeProteus() = runTest { assertEquals(SupportedProtocolEntity.PROTEUS, userConfigStorage.defaultProtocol()) } @Test - fun givenDefaultProtocolIsSetToMls_whenGettingItsValue_thenItShouldBeMls() { + fun givenDefaultProtocolIsSetToMls_whenGettingItsValue_thenItShouldBeMls() = runTest { userConfigStorage.persistDefaultProtocol(SupportedProtocolEntity.MLS) assertEquals(SupportedProtocolEntity.MLS, userConfigStorage.defaultProtocol()) } diff --git a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UnreadContentMapperTest.kt b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UnreadContentMapperTest.kt index 5e94e7470d7..e9bfb31515e 100644 --- a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UnreadContentMapperTest.kt +++ b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UnreadContentMapperTest.kt @@ -19,6 +19,7 @@ package com.wire.kalium.persistence.dao import com.wire.kalium.persistence.dao.message.MessageEntity +import com.wire.kalium.persistence.dao.unread.UnreadContentMapper import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals diff --git a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAOTest.kt b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAOTest.kt new file mode 100644 index 00000000000..cce3490a258 --- /dev/null +++ b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAOTest.kt @@ -0,0 +1,287 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +package com.wire.kalium.persistence.dao + +import app.cash.turbine.test +import com.wire.kalium.persistence.config.AppLockConfigEntity +import com.wire.kalium.persistence.config.ClassifiedDomainsEntity +import com.wire.kalium.persistence.config.IsFileSharingEnabledEntity +import com.wire.kalium.persistence.config.IsGuestRoomLinkEnabledEntity +import io.mockative.any +import io.mockative.coEvery +import io.mockative.eq +import io.mockative.every +import io.mockative.mock +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +internal class UserPrefsDAOTest { + + @Test + fun givenAFileSharingStatusValue_whenCAllPersistItSaveAnd_thenCanRestoreTheValueLocally() = runTest { + val expected1 = IsFileSharingEnabledEntity(true, null) + val expected2 = IsFileSharingEnabledEntity(false, null) + val (_, userConfigStorage) = Arrangement() + .withSerializablePutSucceeding() + .withSerializableGetSucceeding("file_sharing", expected1) + .arrange() + userConfigStorage.persistFileSharingStatus(true, null) + assertEquals(expected1, userConfigStorage.isFileSharingEnabled()) + + Arrangement() + .withSerializablePutSucceeding() + .withSerializableGetSucceeding("file_sharing", expected2) + .arrange() + .let { (_, storage) -> + storage.persistFileSharingStatus(false, null) + assertEquals(expected2, storage.isFileSharingEnabled()) + } + } + + @Test + fun givenAClassifiedDomainsStatusValue_whenCAllPersistItSaveAndThenCanRestoreTheValueLocally() = runTest { + val expected = ClassifiedDomainsEntity(true, listOf("bella.com", "anta.wire")) + val (_, userConfigStorage) = Arrangement() + .withSerializablePutSucceeding() + .withSerializableObserveSucceeding("enable_classified_domains", expected) + .arrange() + userConfigStorage.persistClassifiedDomainsStatus(true, listOf("bella.com", "anta.wire")) + assertEquals( + expected, + userConfigStorage.isClassifiedDomainsEnabledFlow().first() + ) + } + + @Test + fun givenAClassifiedDomainsStatusNotExists_whenCAllPersistItSaveAndThenCanRestoreTheValueLocally() = runTest { + val (_, userConfigStorage) = Arrangement() + .withSerializableObserveReturningNull("enable_classified_domains") + .arrange() + + userConfigStorage.isClassifiedDomainsEnabledFlow().test { + val item = awaitItem() + assertEquals(null, item) + awaitComplete() + } + } + + @Test + fun givenAConferenceCallingStatusValue_whenPersistingIt_saveAndThenRestoreTheValueLocally() = runTest { + val (_, userConfigStorage) = Arrangement() + .withMetadataInserted() + .withMetadataRetrieved("enable_conference_calling", "true") + .arrange() + userConfigStorage.persistConferenceCalling(true) + assertEquals( + true, + userConfigStorage.isConferenceCallingEnabled() + ) + } + + @Test + fun givenAReadReceiptsSetValue_whenPersistingIt_saveAndThenRestoreTheValueLocally() = runTest { + val (_, userConfigStorage) = Arrangement() + .withMetadataInserted() + .withValueByKeyFlowSucceeding("enable_read_receipts", "true") + .arrange() + userConfigStorage.persistReadReceipts(true) + assertTrue(userConfigStorage.areReadReceiptsEnabled().first()) + } + + @Test + fun whenMarkingFileSharingAsNotified_thenIsChangedIsSetToFalse() = runTest { + val statusWithChanged = IsFileSharingEnabledEntity(true, true) + val statusWithoutChanged = IsFileSharingEnabledEntity(true, false) + val (_, userConfigStorage) = Arrangement() + .withSerializablePutSucceeding() + .withSerializableGetSucceeding("file_sharing", statusWithChanged) + .arrange() + userConfigStorage.persistFileSharingStatus(true, true) + + Arrangement() + .withSerializablePutSucceeding() + .withSerializableGetSucceeding("file_sharing", statusWithoutChanged) + .arrange() + .let { (_, storage) -> + storage.setFileSharingAsNotified() + assertEquals(statusWithoutChanged, storage.isFileSharingEnabled()) + } + } + + @Test + fun givenPasswordChallengeRequirementIsNotSet_whenGettingItsValue_thenItShouldBeFalseByDefault() = runTest { + val (_, userConfigStorage) = Arrangement() + .withNoMetadataRetrieved("require_second_factor_password_challenge") + .arrange() + assertFalse { + userConfigStorage.isSecondFactorPasswordChallengeRequired() + } + } + + @Test + fun givenPasswordChallengeRequirementIsSetToFalse_whenGettingItsValue_thenItShouldBeFalse() = runTest { + val (_, userConfigStorage) = Arrangement() + .withMetadataInserted() + .withMetadataRetrieved("require_second_factor_password_challenge", "false") + .arrange() + userConfigStorage.persistSecondFactorPasswordChallengeStatus(false) + assertFalse { + userConfigStorage.isSecondFactorPasswordChallengeRequired() + } + } + + @Test + fun givenPasswordChallengeRequirementIsSetToTrue_whenGettingItsValue_thenItShouldBeTrue() = runTest { + val (_, userConfigStorage) = Arrangement() + .withMetadataInserted() + .withMetadataRetrieved("require_second_factor_password_challenge", "true") + .arrange() + userConfigStorage.persistSecondFactorPasswordChallengeStatus(true) + assertTrue { + userConfigStorage.isSecondFactorPasswordChallengeRequired() + } + } + + @Test + fun givenGuestRoomLinkStatusIsSetToFalse_whenGettingItsValue_thenItShouldBeFalse() = runTest { + val expected = IsGuestRoomLinkEnabledEntity(false, false) + val (_, userConfigStorage) = Arrangement() + .withSerializablePutSucceeding() + .withSerializableGetSucceeding("guest_room_link", expected) + .arrange() + userConfigStorage.persistGuestRoomLinkFeatureFlag(status = false, isStatusChanged = false) + userConfigStorage.isGuestRoomLinkEnabled()?.status?.let { + assertFalse { it } + } + } + + @Test + fun givenGuestRoomLinkStatusIsSetToTrue_whenGettingItsValue_thenItShouldBeTrue() = runTest { + val expected = IsGuestRoomLinkEnabledEntity(true, false) + val (_, userConfigStorage) = Arrangement() + .withSerializablePutSucceeding() + .withSerializableGetSucceeding("guest_room_link", expected) + .arrange() + userConfigStorage.persistGuestRoomLinkFeatureFlag(status = true, isStatusChanged = false) + userConfigStorage.isGuestRoomLinkEnabled()?.status?.let { + assertTrue { it } + } + } + + @Test + fun givenScreenshotCensoringConfigIsSetToFalse_whenGettingItsValue_thenItShouldBeFalse() = runTest { + val (_, userConfigStorage) = Arrangement() + .withMetadataInserted() + .withValueByKeyFlowSucceeding("enable_screenshot_censoring", "false") + .arrange() + userConfigStorage.persistScreenshotCensoring(enabled = false) + assertEquals(false, userConfigStorage.isScreenshotCensoringEnabledFlow().first()) + } + + @Test + fun givenScreenshotCensoringConfigIsSetToTrue_whenGettingItsValue_thenItShouldBeTrue() = runTest { + val (_, userConfigStorage) = Arrangement() + .withMetadataInserted() + .withValueByKeyFlowSucceeding("enable_screenshot_censoring", "true") + .arrange() + userConfigStorage.persistScreenshotCensoring(enabled = true) + assertEquals(true, userConfigStorage.isScreenshotCensoringEnabledFlow().first()) + } + + @Test + fun givenAppLockConfig_whenStoring_thenItCanBeRead() = runTest { + val expected = AppLockConfigEntity( + enforceAppLock = true, + inactivityTimeoutSecs = 60, + isStatusChanged = false + ) + val (_, userConfigStorage) = Arrangement() + .withSerializablePutSucceeding() + .withSerializableGetSucceeding("app_lock", expected) + .arrange() + userConfigStorage.persistAppLockStatus( + expected.enforceAppLock, + expected.inactivityTimeoutSecs, + expected.isStatusChanged + ) + assertEquals(expected, userConfigStorage.appLockStatus()) + } + + @Test + fun givenDefaultProtocolIsNotSet_whenGettingItsValue_thenItShouldBeProteus() = runTest { + val (_, userConfigStorage) = Arrangement() + .withNoMetadataRetrieved("default_protocol") + .arrange() + assertEquals(SupportedProtocolEntity.PROTEUS, userConfigStorage.defaultProtocol()) + } + + @Test + fun givenDefaultProtocolIsSetToMls_whenGettingItsValue_thenItShouldBeMls() = runTest { + val (_, userConfigStorage) = Arrangement() + .withMetadataInserted() + .withMetadataRetrieved("default_protocol", "MLS") + .arrange() + userConfigStorage.persistDefaultProtocol(SupportedProtocolEntity.MLS) + assertEquals(SupportedProtocolEntity.MLS, userConfigStorage.defaultProtocol()) + } + + private class Arrangement { + val metadataDAO = mock(MetadataDAO::class) + + suspend fun withMetadataInserted() = apply { + coEvery { metadataDAO.insertValue(any(), any()) } returns Unit + } + + suspend fun withMetadataRetrieved(key: String, value: String?) = apply { + coEvery { metadataDAO.valueByKey(eq(key)) } returns value + } + + suspend fun withNoMetadataRetrieved(key: String) = apply { + coEvery { metadataDAO.valueByKey(eq(key)) } returns null + } + + suspend fun withSerializablePutSucceeding() = apply { + coEvery { metadataDAO.putSerializable(any(), any(), any()) } returns Unit + } + + suspend fun withSerializableGetSucceeding(key: String, value: Any?) = apply { + coEvery { metadataDAO.getSerializable(eq(key), any>()) } returns value + } + + fun withSerializableObserveSucceeding(key: String, value: Any?) = apply { + every { metadataDAO.observeSerializable(eq(key), any>()) } returns flowOf(value) + } + + fun withSerializableObserveReturningNull(key: String) = apply { + every { metadataDAO.observeSerializable(eq(key), any>()) } returns flowOf(null) + } + + suspend fun withValueByKeyFlowSucceeding(key: String, value: String?) = apply { + coEvery { metadataDAO.valueByKeyFlow(eq(key)) } returns flowOf(value) + } + + fun arrange() = this to UserPrefsDAO(metadataDAO) + + } +} diff --git a/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/CellsScope.kt b/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/CellsScope.kt index 5b6b6f968b3..0528ea18bcd 100644 --- a/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/CellsScope.kt +++ b/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/CellsScope.kt @@ -126,7 +126,7 @@ import com.wire.kalium.persistence.dao.conversation.ConversationDAO import com.wire.kalium.persistence.dao.message.attachment.MessageAttachmentsDao import com.wire.kalium.persistence.dao.messageattachment.MessageAttachmentDraftDao import com.wire.kalium.persistence.dao.publiclink.PublicLinkDao -import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAO import io.ktor.client.HttpClient import io.ktor.client.plugins.HttpRedirect import kotlinx.coroutines.CoroutineScope diff --git a/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/data/CellConfigDataSource.kt b/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/data/CellConfigDataSource.kt index 1c526500c9f..bc35a410554 100644 --- a/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/data/CellConfigDataSource.kt +++ b/domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/data/CellConfigDataSource.kt @@ -23,7 +23,7 @@ import com.wire.kalium.common.error.StorageFailure import com.wire.kalium.common.error.wrapStorageRequest import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.data.featureConfig.CollaboraEdition.Companion.fromString -import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAO internal class CellConfigDataSource( private val userConfigDAO: UserConfigDAO, diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt index 558a82e8f0a..32be9370af7 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt @@ -23,7 +23,6 @@ import com.wire.kalium.common.error.StorageFailure import com.wire.kalium.common.error.wrapFlowStorageRequest import com.wire.kalium.common.error.wrapStorageRequest import com.wire.kalium.common.functional.Either -import com.wire.kalium.common.functional.getOrNull import com.wire.kalium.common.functional.isLeft import com.wire.kalium.common.functional.map import com.wire.kalium.common.functional.mapRight @@ -48,7 +47,7 @@ import com.wire.kalium.persistence.config.IsFileSharingEnabledEntity import com.wire.kalium.persistence.config.TeamSettingsSelfDeletionStatusEntity import com.wire.kalium.persistence.config.UserConfigStorage import com.wire.kalium.persistence.config.WireCellsConfigEntity -import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAO import com.wire.kalium.persistence.model.SupportedCipherSuiteEntity import com.wire.kalium.util.DateTimeUtil import io.mockative.Mockable @@ -64,54 +63,54 @@ import kotlin.time.Duration.Companion.seconds @Suppress("TooManyFunctions") @Mockable internal interface UserConfigRepository { - fun setAppLockStatus( + suspend fun setAppLockStatus( isAppLocked: Boolean, timeout: Int, isStatusChanged: Boolean? ): Either - fun isTeamAppLockEnabled(): Either + suspend fun isTeamAppLockEnabled(): Either fun observeAppLockConfig(): Flow> - fun setTeamAppLockAsNotified(): Either - fun setFileSharingStatus( + suspend fun setTeamAppLockAsNotified(): Either + suspend fun setFileSharingStatus( status: Boolean, isStatusChanged: Boolean? ): Either - fun setFileSharingAsNotified(): Either - fun isFileSharingEnabled(): Either + suspend fun setFileSharingAsNotified(): Either + suspend fun isFileSharingEnabled(): Either fun isFileSharingEnabledFlow(): Flow> - fun setClassifiedDomainsStatus( + suspend fun setClassifiedDomainsStatus( enabled: Boolean, domains: List ): Either fun getClassifiedDomainsStatus(): Flow> suspend fun isMLSEnabled(): Either - fun setMLSEnabled(enabled: Boolean): Either - fun getE2EISettings(): Either + suspend fun setMLSEnabled(enabled: Boolean): Either + suspend fun getE2EISettings(): Either fun observeE2EISettings(): Flow> - fun setE2EISettings(setting: E2EISettings): Either - fun snoozeE2EINotification(duration: Duration): Either - fun setDefaultProtocol(protocol: SupportedProtocol): Either + suspend fun setE2EISettings(setting: E2EISettings): Either + suspend fun snoozeE2EINotification(duration: Duration): Either + suspend fun setDefaultProtocol(protocol: SupportedProtocol): Either suspend fun setSupportedCipherSuite(cipherSuite: SupportedCipherSuite): Either suspend fun getSupportedCipherSuite(): Either - fun getDefaultProtocol(): Either + suspend fun getDefaultProtocol(): Either suspend fun setSupportedProtocols(protocols: Set): Either suspend fun getSupportedProtocols(): Either> - fun setConferenceCallingEnabled(enabled: Boolean): Either - fun isConferenceCallingEnabled(): Either - fun observeConferenceCallingEnabled(): Flow> - fun setUseSFTForOneOnOneCalls(shouldUse: Boolean): Either + suspend fun setConferenceCallingEnabled(enabled: Boolean): Either + suspend fun isConferenceCallingEnabled(): Either + suspend fun observeConferenceCallingEnabled(): Flow> + suspend fun setUseSFTForOneOnOneCalls(shouldUse: Boolean): Either suspend fun shouldUseSFTForOneOnOneCalls(): Either - fun setSecondFactorPasswordChallengeStatus(isRequired: Boolean): Either - fun isSecondFactorPasswordChallengeRequired(): Either - fun isReadReceiptsEnabled(): Flow> - fun setReadReceiptsStatus(enabled: Boolean): Either - fun isTypingIndicatorEnabled(): Flow> - fun setTypingIndicatorStatus(enabled: Boolean): Either - fun setGuestRoomStatus(status: Boolean, isStatusChanged: Boolean?): Either - fun getGuestRoomLinkStatus(): Either + suspend fun setSecondFactorPasswordChallengeStatus(isRequired: Boolean): Either + suspend fun isSecondFactorPasswordChallengeRequired(): Either + suspend fun isReadReceiptsEnabled(): Flow> + suspend fun setReadReceiptsStatus(enabled: Boolean): Either + suspend fun isTypingIndicatorEnabled(): Flow> + suspend fun setTypingIndicatorStatus(enabled: Boolean): Either + suspend fun setGuestRoomStatus(status: Boolean, isStatusChanged: Boolean?): Either + suspend fun getGuestRoomLinkStatus(): Either fun observeGuestRoomLinkFeatureFlag(): Flow> suspend fun setScreenshotCensoringConfig(enabled: Boolean): Either suspend fun observeScreenshotCensoringConfig(): Flow> @@ -123,8 +122,8 @@ internal interface UserConfigRepository { suspend fun markTeamSettingsSelfDeletingMessagesStatusAsNotified(): Either suspend fun observeTeamSettingsSelfDeletingStatus(): Flow> - fun observeE2EINotificationTime(): Flow> - fun setE2EINotificationTime(instant: Instant): Either + suspend fun observeE2EINotificationTime(): Flow> + suspend fun setE2EINotificationTime(instant: Instant): Either suspend fun getMigrationConfiguration(): Either suspend fun setMigrationConfiguration(configuration: MLSMigrationModel): Either suspend fun setLegalHoldRequest( @@ -179,17 +178,17 @@ internal class UserConfigDataSource internal constructor( private val kaliumConfigs: KaliumConfigs ) : UserConfigRepository { - override fun setFileSharingStatus( + override suspend fun setFileSharingStatus( status: Boolean, isStatusChanged: Boolean? ): Either = wrapStorageRequest { userConfigStorage.persistFileSharingStatus(status, isStatusChanged) } - override fun setFileSharingAsNotified(): Either = wrapStorageRequest { + override suspend fun setFileSharingAsNotified(): Either = wrapStorageRequest { userConfigStorage.setFileSharingAsNotified() } - override fun isFileSharingEnabled(): Either { + override suspend fun isFileSharingEnabled(): Either { val serverSideConfig = wrapStorageRequest { userConfigStorage.isFileSharingEnabled() } val buildConfig = kaliumConfigs.fileRestrictionState return deriveFileSharingStatus(serverSideConfig, buildConfig) @@ -233,7 +232,7 @@ internal class UserConfigDataSource internal constructor( else -> error("Unknown file restriction state: buildConfig: $buildConfig , serverConfig: $serverSideConfig") } - override fun setClassifiedDomainsStatus(enabled: Boolean, domains: List) = + override suspend fun setClassifiedDomainsStatus(enabled: Boolean, domains: List) = wrapStorageRequest { userConfigStorage.persistClassifiedDomainsStatus(enabled, domains) } override fun getClassifiedDomainsStatus(): Flow> = @@ -247,10 +246,10 @@ internal class UserConfigDataSource internal constructor( wrapStorageRequest { userConfigStorage.isMLSEnabled() } } - override fun setMLSEnabled(enabled: Boolean): Either = + override suspend fun setMLSEnabled(enabled: Boolean): Either = wrapStorageRequest { userConfigStorage.enableMLS(enabled) } - override fun getE2EISettings(): Either = + override suspend fun getE2EISettings(): Either = wrapStorageRequest { userConfigStorage.getE2EISettings() } .map { E2EISettings.fromEntity(it) } @@ -259,18 +258,18 @@ internal class UserConfigDataSource internal constructor( .wrapStorageRequest() .mapRight { E2EISettings.fromEntity(it) } - override fun setE2EISettings(setting: E2EISettings): Either = + override suspend fun setE2EISettings(setting: E2EISettings): Either = wrapStorageRequest { userConfigStorage.setE2EISettings(setting.toEntity()) } - override fun observeE2EINotificationTime(): Flow> = + override suspend fun observeE2EINotificationTime(): Flow> = userConfigStorage.e2EINotificationTimeFlow() .wrapStorageRequest() .mapRight { Instant.fromEpochMilliseconds(it) } - override fun setE2EINotificationTime(instant: Instant): Either = + override suspend fun setE2EINotificationTime(instant: Instant): Either = wrapStorageRequest { userConfigStorage.setIfAbsentE2EINotificationTime(instant.toEpochMilliseconds()) } - override fun snoozeE2EINotification(duration: Duration): Either = + override suspend fun snoozeE2EINotification(duration: Duration): Either = wrapStorageRequest { val notifyUserAfterMs = DateTimeUtil.currentInstant().toEpochMilliseconds().plus(duration.inWholeMilliseconds) userConfigStorage.updateE2EINotificationTime(notifyUserAfterMs) @@ -283,10 +282,7 @@ internal class UserConfigDataSource internal constructor( } } - private fun getE2EINotificationTimeOrNull() = - wrapStorageRequest { userConfigStorage.getE2EINotificationTime() }.getOrNull() - - override fun setDefaultProtocol(protocol: SupportedProtocol): Either = + override suspend fun setDefaultProtocol(protocol: SupportedProtocol): Either = wrapStorageRequest { userConfigStorage.persistDefaultProtocol(protocol.toDao()) } override suspend fun setSupportedCipherSuite(cipherSuite: SupportedCipherSuite): Either = @@ -308,7 +304,7 @@ internal class UserConfigDataSource internal constructor( ) } - override fun getDefaultProtocol(): Either = + override suspend fun getDefaultProtocol(): Either = wrapStorageRequest { userConfigStorage.defaultProtocol().toModel() } override suspend fun setSupportedProtocols(protocols: Set): Either = @@ -317,20 +313,20 @@ internal class UserConfigDataSource internal constructor( override suspend fun getSupportedProtocols(): Either> = wrapStorageRequest { userConfigDAO.getSupportedProtocols()?.toModel() } - override fun setConferenceCallingEnabled(enabled: Boolean): Either = + override suspend fun setConferenceCallingEnabled(enabled: Boolean): Either = wrapStorageRequest { userConfigStorage.persistConferenceCalling(enabled) } - override fun isConferenceCallingEnabled(): Either = + override suspend fun isConferenceCallingEnabled(): Either = wrapStorageRequest { userConfigStorage.isConferenceCallingEnabled() } - override fun observeConferenceCallingEnabled(): Flow> = + override suspend fun observeConferenceCallingEnabled(): Flow> = userConfigStorage.isConferenceCallingEnabledFlow().wrapStorageRequest() - override fun setUseSFTForOneOnOneCalls(shouldUse: Boolean): Either = wrapStorageRequest { + override suspend fun setUseSFTForOneOnOneCalls(shouldUse: Boolean): Either = wrapStorageRequest { userConfigStorage.persistUseSftForOneOnOneCalls(shouldUse) } @@ -340,33 +336,33 @@ internal class UserConfigDataSource internal constructor( } } - override fun setSecondFactorPasswordChallengeStatus(isRequired: Boolean): Either = + override suspend fun setSecondFactorPasswordChallengeStatus(isRequired: Boolean): Either = wrapStorageRequest { userConfigStorage.persistSecondFactorPasswordChallengeStatus(isRequired) } - override fun isSecondFactorPasswordChallengeRequired(): Either = + override suspend fun isSecondFactorPasswordChallengeRequired(): Either = wrapStorageRequest { userConfigStorage.isSecondFactorPasswordChallengeRequired() } - override fun isReadReceiptsEnabled(): Flow> = + override suspend fun isReadReceiptsEnabled(): Flow> = userConfigStorage.areReadReceiptsEnabled().wrapStorageRequest() - override fun setReadReceiptsStatus(enabled: Boolean): Either = + override suspend fun setReadReceiptsStatus(enabled: Boolean): Either = wrapStorageRequest { userConfigStorage.persistReadReceipts(enabled) } - override fun isTypingIndicatorEnabled(): Flow> = + override suspend fun isTypingIndicatorEnabled(): Flow> = userConfigStorage.isTypingIndicatorEnabled().wrapStorageRequest() - override fun setTypingIndicatorStatus(enabled: Boolean): Either = + override suspend fun setTypingIndicatorStatus(enabled: Boolean): Either = wrapStorageRequest { userConfigStorage.persistTypingIndicator(enabled) } - override fun setGuestRoomStatus( + override suspend fun setGuestRoomStatus( status: Boolean, isStatusChanged: Boolean? ): Either = @@ -374,7 +370,7 @@ internal class UserConfigDataSource internal constructor( userConfigStorage.persistGuestRoomLinkFeatureFlag(status, isStatusChanged) } - override fun getGuestRoomLinkStatus(): Either = + override suspend fun getGuestRoomLinkStatus(): Either = wrapStorageRequest { userConfigStorage.isGuestRoomLinkEnabled() }.map { with(it) { GuestRoomLinkStatus(status, isStatusChanged) } } @@ -434,7 +430,7 @@ internal class UserConfigDataSource internal constructor( override suspend fun observeScreenshotCensoringConfig(): Flow> = userConfigStorage.isScreenshotCensoringEnabledFlow().wrapStorageRequest() - override fun setAppLockStatus( + override suspend fun setAppLockStatus( isAppLocked: Boolean, timeout: Int, isStatusChanged: Boolean? @@ -460,7 +456,7 @@ internal class UserConfigDataSource internal constructor( } } - override fun isTeamAppLockEnabled(): Either = + override suspend fun isTeamAppLockEnabled(): Either = wrapStorageRequest { userConfigStorage.appLockStatus() }.map { @@ -471,7 +467,7 @@ internal class UserConfigDataSource internal constructor( ) } - override fun setTeamAppLockAsNotified(): Either = wrapStorageRequest { + override suspend fun setTeamAppLockAsNotified(): Either = wrapStorageRequest { userConfigStorage.setTeamAppLockAsNotified() } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepository.kt index a66aaa8ae3c..fa56d1d7bf5 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepository.kt @@ -97,7 +97,7 @@ internal interface E2EIRepository { suspend fun initiateMLSClient(certificateChain: String): Either suspend fun nukeE2EIClient() suspend fun fetchFederationCertificates(): Either - fun discoveryUrl(): Either + suspend fun discoveryUrl(): Either } @Suppress("LongParameterList") @@ -384,7 +384,7 @@ internal class E2EIRepositoryImpl( }) }) - override fun discoveryUrl() = + override suspend fun discoveryUrl() = userConfigRepository.getE2EISettings().fold({ E2EIFailure.MissingTeamSettings.left() }, { settings -> diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/team/TeamRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/team/TeamRepository.kt index 32005d7d5af..bc74b7efcb4 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/team/TeamRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/team/TeamRepository.kt @@ -45,7 +45,7 @@ import com.wire.kalium.persistence.dao.ServiceDAO import com.wire.kalium.persistence.dao.TeamDAO import com.wire.kalium.persistence.dao.UserDAO import com.wire.kalium.persistence.dao.message.LocalId -import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAO import io.mockative.Mockable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 1460b30a35e..a19b1e1ba50 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -707,7 +707,7 @@ public class UserSessionScope internal constructor( internal val userConfigRepository: UserConfigRepository get() = UserConfigDataSource( - userStorage.preferences.userConfigStorage, + userStorage.database.userPrefsDAO, userStorage.database.userConfigDAO, kaliumConfigs ) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCase.kt index ebbc81286e7..1d00fca7daf 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCase.kt @@ -25,13 +25,13 @@ import com.wire.kalium.logic.configuration.UserConfigRepository * e.g. after showing a dialog, or a toast etc. */ public interface MarkTeamAppLockStatusAsNotifiedUseCase { - public operator fun invoke() + public suspend operator fun invoke() } internal class MarkTeamAppLockStatusAsNotifiedUseCaseImpl internal constructor( private val userConfigRepository: UserConfigRepository ) : MarkTeamAppLockStatusAsNotifiedUseCase { - override operator fun invoke() { + override suspend operator fun invoke() { userConfigRepository.setTeamAppLockAsNotified() } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCase.kt index 66b71413098..e64daa912de 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCase.kt @@ -67,7 +67,7 @@ internal class IsEligibleToStartCallUseCaseImpl( else -> ConferenceCallingResult.Disabled.Unavailable } - private fun isConferenceCallingEnabled(): Boolean = userConfigRepository + private suspend fun isConferenceCallingEnabled(): Boolean = userConfigRepository .isConferenceCallingEnabled() .fold({ DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandler.kt index 902a90bb81e..89ee19af3be 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandler.kt @@ -28,7 +28,7 @@ import com.wire.kalium.common.functional.nullableFold internal class AppLockConfigHandler internal constructor( private val userConfigRepository: UserConfigRepository ) { - fun handle(appLockConfig: AppLockModel): Either { + suspend fun handle(appLockConfig: AppLockModel): Either { val isStatusChanged = userConfigRepository.isTeamAppLockEnabled().nullableFold( { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ClassifiedDomainsConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ClassifiedDomainsConfigHandler.kt index afc2a234d2b..67726d31065 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ClassifiedDomainsConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ClassifiedDomainsConfigHandler.kt @@ -26,7 +26,7 @@ import com.wire.kalium.common.functional.Either internal class ClassifiedDomainsConfigHandler internal constructor( private val userConfigRepository: UserConfigRepository ) { - fun handle(classifiedDomainsConfig: ClassifiedDomainsModel): Either { + suspend fun handle(classifiedDomainsConfig: ClassifiedDomainsModel): Either { val classifiedDomainsEnabled = classifiedDomainsConfig.status == Status.ENABLED return userConfigRepository.setClassifiedDomainsStatus(classifiedDomainsEnabled, classifiedDomainsConfig.config.domains) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandler.kt index 64fd7e761fd..e497afa88a4 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandler.kt @@ -27,7 +27,7 @@ import com.wire.kalium.common.functional.flatMap internal class ConferenceCallingConfigHandler( private val userConfigRepository: UserConfigRepository ) { - internal fun handle(conferenceCallingConfig: ConferenceCallingModel): Either { + internal suspend fun handle(conferenceCallingConfig: ConferenceCallingModel): Either { val conferenceCallingEnabled = conferenceCallingConfig.status == Status.ENABLED val result = userConfigRepository.setConferenceCallingEnabled(conferenceCallingEnabled).flatMap { userConfigRepository.setUseSFTForOneOnOneCalls(conferenceCallingConfig.useSFTForOneOnOneCalls) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/E2EIConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/E2EIConfigHandler.kt index 014c2a7760e..e61b11bdf16 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/E2EIConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/E2EIConfigHandler.kt @@ -30,12 +30,12 @@ import kotlin.time.toDuration internal class E2EIConfigHandler(private val userConfigRepository: UserConfigRepository) { - internal fun handle(e2eiConfig: E2EIModel): Either { + internal suspend fun handle(e2eiConfig: E2EIModel): Either { setSettingsIfNeeded(e2eiConfig) return userConfigRepository.setE2EINotificationTime(DateTimeUtil.currentInstant()) } - private fun setSettingsIfNeeded(e2eiConfig: E2EIModel) { + private suspend fun setSettingsIfNeeded(e2eiConfig: E2EIModel) { val gracePeriodEnd = e2eiConfig.config.verificationExpirationSeconds .toDuration(DurationUnit.SECONDS) .let { DateTimeUtil.currentInstant().plus(it) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/FileSharingConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/FileSharingConfigHandler.kt index 9ab34aaddcd..1b980297aaa 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/FileSharingConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/FileSharingConfigHandler.kt @@ -27,10 +27,9 @@ import com.wire.kalium.common.functional.Either internal class FileSharingConfigHandler( private val userConfigRepository: UserConfigRepository, ) { - internal fun handle(fileSharingConfig: ConfigsStatusModel): Either { + internal suspend fun handle(fileSharingConfig: ConfigsStatusModel): Either { val newStatus: Boolean = fileSharingConfig.status == Status.ENABLED - val currentStatus = userConfigRepository.isFileSharingEnabled() - val isStatusChanged: Boolean = when (currentStatus) { + val isStatusChanged: Boolean = when (val currentStatus = userConfigRepository.isFileSharingEnabled()) { is Either.Left -> false is Either.Right -> { when (currentStatus.value.state) { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/GuestRoomConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/GuestRoomConfigHandler.kt index ba9ba6f4040..71cb3f0587b 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/GuestRoomConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/GuestRoomConfigHandler.kt @@ -29,7 +29,7 @@ internal class GuestRoomConfigHandler( private val userConfigRepository: UserConfigRepository, private val kaliumConfigs: KaliumConfigs ) { - internal fun handle(guestRoomConfig: ConfigsStatusModel): Either = + internal suspend fun handle(guestRoomConfig: ConfigsStatusModel): Either = if (!kaliumConfigs.guestRoomLink) { userConfigRepository.setGuestRoomStatus(false, null) } else { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/SecondFactorPasswordChallengeConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/SecondFactorPasswordChallengeConfigHandler.kt index 8cb9cdaf1e3..1815dc9e8b4 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/SecondFactorPasswordChallengeConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/SecondFactorPasswordChallengeConfigHandler.kt @@ -26,7 +26,7 @@ import com.wire.kalium.common.functional.Either internal class SecondFactorPasswordChallengeConfigHandler( private val userConfigRepository: UserConfigRepository ) { - internal fun handle(secondFactorPasswordChallengeConfig: ConfigsStatusModel): Either { + internal suspend fun handle(secondFactorPasswordChallengeConfig: ConfigsStatusModel): Either { val isRequired = secondFactorPasswordChallengeConfig.status == Status.ENABLED return userConfigRepository.setSecondFactorPasswordChallengeStatus(isRequired) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCase.kt index 2942236a0be..b3bb998ce86 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCase.kt @@ -30,14 +30,14 @@ public interface GetDefaultProtocolUseCase { /** * @return [SupportedProtocol.MLS] or [SupportedProtocol.PROTEUS] */ - public operator fun invoke(): SupportedProtocol + public suspend operator fun invoke(): SupportedProtocol } internal class GetDefaultProtocolUseCaseImpl( private val userConfigRepository: UserConfigRepository ) : GetDefaultProtocolUseCase { - override fun invoke(): SupportedProtocol = + override suspend fun invoke(): SupportedProtocol = userConfigRepository.getDefaultProtocol().fold({ SupportedProtocol.PROTEUS }, { supportedProtocol -> diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/IsFileSharingEnabledUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/IsFileSharingEnabledUseCase.kt index e12cd6975a9..9080cbe25f2 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/IsFileSharingEnabledUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/IsFileSharingEnabledUseCase.kt @@ -28,14 +28,14 @@ import com.wire.kalium.common.functional.fold */ public interface IsFileSharingEnabledUseCase { - public operator fun invoke(): FileSharingStatus + public suspend operator fun invoke(): FileSharingStatus } internal class IsFileSharingEnabledUseCaseImpl( private val userConfigRepository: UserConfigRepository ) : IsFileSharingEnabledUseCase { - override operator fun invoke(): FileSharingStatus = + override suspend operator fun invoke(): FileSharingStatus = userConfigRepository.isFileSharingEnabled() .fold({ FileSharingStatus(FileSharingStatus.Value.Disabled, false) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/ObserveE2EIRequiredUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/ObserveE2EIRequiredUseCase.kt index 3abfb6925ac..160cfbc1a03 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/ObserveE2EIRequiredUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/ObserveE2EIRequiredUseCase.kt @@ -51,7 +51,7 @@ public interface ObserveE2EIRequiredUseCase { /** * @return [Flow] of [E2EIRequiredResult] */ - public operator fun invoke(): Flow + public suspend operator fun invoke(): Flow } internal class ObserveE2EIRequiredUseCaseImpl( @@ -64,7 +64,7 @@ internal class ObserveE2EIRequiredUseCaseImpl( ) : ObserveE2EIRequiredUseCase { @OptIn(ExperimentalCoroutinesApi::class) - override fun invoke(): Flow { + override suspend fun invoke(): Flow { if (!featureSupport.isMLSSupported) return flowOf(E2EIRequiredResult.NotRequired) return userConfigRepository diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCase.kt index 90f87ce61f0..96766d2aba4 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCase.kt @@ -25,13 +25,13 @@ import com.wire.kalium.common.functional.onSuccess * Mark Guest Link Feature Flag state as not changed */ public interface MarkGuestLinkFeatureFlagAsNotChangedUseCase { - public operator fun invoke() + public suspend operator fun invoke() } internal class MarkGuestLinkFeatureFlagAsNotChangedUseCaseImpl internal constructor( private val userConfigRepository: UserConfigRepository ) : MarkGuestLinkFeatureFlagAsNotChangedUseCase { - override operator fun invoke() { + override suspend operator fun invoke() { userConfigRepository.getGuestRoomLinkStatus().onSuccess { it.isStatusChanged?.let { isEnabled -> userConfigRepository.setGuestRoomStatus(isEnabled, false) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiver.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiver.kt index 1fe3871d550..de3af0fea1e 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiver.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiver.kt @@ -59,7 +59,7 @@ internal class UserPropertiesEventReceiverImpl internal constructor( } } - private fun handleReadReceiptMode( + private suspend fun handleReadReceiptMode( event: Event.UserProperty.ReadReceiptModeSet ): Either { val logger = kaliumLogger.createEventProcessingLogger(event) @@ -69,7 +69,7 @@ internal class UserPropertiesEventReceiverImpl internal constructor( .onFailure { logger.logFailure(it) } } - private fun handleTypingIndicatorMode( + private suspend fun handleTypingIndicatorMode( event: Event.UserProperty.TypingIndicatorModeSet ): Either { val logger = kaliumLogger.createEventProcessingLogger(event) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/CertificateRevocationListRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/CertificateRevocationListRepositoryTest.kt index 60e5c170ea7..24a4a52f918 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/CertificateRevocationListRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/CertificateRevocationListRepositoryTest.kt @@ -18,11 +18,11 @@ package com.wire.kalium.logic.data.e2ei import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either +import com.wire.kalium.common.functional.right import com.wire.kalium.logic.configuration.E2EISettings import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.e2ei.CertificateRevocationListRepositoryDataSource.Companion.CRL_LIST_KEY -import com.wire.kalium.common.functional.Either -import com.wire.kalium.common.functional.right import com.wire.kalium.network.api.base.unbound.acme.ACMEApi import com.wire.kalium.network.utils.NetworkResponse import com.wire.kalium.persistence.config.CRLUrlExpirationList @@ -30,11 +30,9 @@ import com.wire.kalium.persistence.config.CRLWithExpiration import com.wire.kalium.persistence.dao.MetadataDAO import dev.mokkery.MockMode import dev.mokkery.answering.returns -import dev.mokkery.every import dev.mokkery.everySuspend import dev.mokkery.matcher.any import dev.mokkery.mock -import dev.mokkery.verify import dev.mokkery.verifySuspend import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -123,7 +121,7 @@ class CertificateRevocationListRepositoryTest { crlRepository.getClientDomainCRL(DUMMY_URL2) - verify { arrangement.userConfigRepository.getE2EISettings() } + verifySuspend { arrangement.userConfigRepository.getE2EISettings() } verifySuspend { arrangement.acmeApi.getClientDomainCRL(DUMMY_URL2, DUMMY_URL) } } @@ -137,7 +135,7 @@ class CertificateRevocationListRepositoryTest { crlRepository.getClientDomainCRL(DUMMY_URL2) - verify { arrangement.userConfigRepository.getE2EISettings() } + verifySuspend { arrangement.userConfigRepository.getE2EISettings() } verifySuspend { arrangement.acmeApi.getClientDomainCRL(DUMMY_URL2, null) @@ -153,7 +151,7 @@ class CertificateRevocationListRepositoryTest { crlRepository.getClientDomainCRL(DUMMY_URL2) - verify { arrangement.userConfigRepository.getE2EISettings() } + verifySuspend { arrangement.userConfigRepository.getE2EISettings() } verifySuspend { arrangement.acmeApi.getClientDomainCRL(DUMMY_URL2, null) @@ -196,11 +194,16 @@ class CertificateRevocationListRepositoryTest { } fun withE2EISettings(result: Either = E2EI_SETTINGS.right()) = apply { - every { userConfigRepository.getE2EISettings() } returns result + everySuspend { userConfigRepository.getE2EISettings() } returns result } fun withClientDomainCRL() = apply { - everySuspend { acmeApi.getClientDomainCRL(any(), any()) } returns NetworkResponse.Success("some_response".encodeToByteArray(), mapOf(), 200) + everySuspend { + acmeApi.getClientDomainCRL( + any(), + any() + ) + } returns NetworkResponse.Success("some_response".encodeToByteArray(), mapOf(), 200) } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepositoryTest.kt index e47c0a56711..f12b5ec00d2 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/E2EIRepositoryTest.kt @@ -62,11 +62,9 @@ import io.mockative.any import io.mockative.coEvery import io.mockative.coVerify import io.mockative.eq -import io.mockative.every import io.mockative.mock import io.mockative.once import io.mockative.time -import io.mockative.verify import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant import kotlin.test.Test @@ -941,7 +939,7 @@ class E2EIRepositoryTest { } @Test - fun givenE2EIIsDisabled_whenCallingDiscoveryUrl_thenItFailWithDisabled() { + fun givenE2EIIsDisabled_whenCallingDiscoveryUrl_thenItFailWithDisabled() = runTest { val (arrangement, e2eiRepository) = Arrangement() .withGettingE2EISettingsReturns(Either.Right(E2EISettings(false, null, Instant.DISTANT_FUTURE, false, null))) .arrange() @@ -950,13 +948,13 @@ class E2EIRepositoryTest { assertIs(it) } - verify { + coVerify { arrangement.userConfigRepository.getE2EISettings() }.wasInvoked(once) } @Test - fun givenE2EIIsEnabledAndDiscoveryUrlIsNull_whenCallingDiscoveryUrl_thenItFailWithMissingDiscoveryUrl() { + fun givenE2EIIsEnabledAndDiscoveryUrlIsNull_whenCallingDiscoveryUrl_thenItFailWithMissingDiscoveryUrl() = runTest { val (arrangement, e2eiRepository) = Arrangement() .withGettingE2EISettingsReturns(Either.Right(E2EISettings(true, null, Instant.DISTANT_FUTURE, false, null))) .arrange() @@ -965,13 +963,13 @@ class E2EIRepositoryTest { assertIs(it) } - verify { + coVerify { arrangement.userConfigRepository.getE2EISettings() }.wasInvoked(once) } @Test - fun givenE2EIIsEnabledAndDiscoveryUrlIsNotNull_whenCallingDiscoveryUrl_thenItSucceed() { + fun givenE2EIIsEnabledAndDiscoveryUrlIsNotNull_whenCallingDiscoveryUrl_thenItSucceed() = runTest { val (arrangement, e2eiRepository) = Arrangement() .withGettingE2EISettingsReturns(Either.Right(E2EISettings(true, RANDOM_URL, Instant.DISTANT_FUTURE, false, null))) .arrange() @@ -980,7 +978,7 @@ class E2EIRepositoryTest { assertEquals(RANDOM_URL, it) } - verify { + coVerify { arrangement.userConfigRepository.getE2EISettings() }.wasInvoked(once) } @@ -1095,8 +1093,8 @@ class E2EIRepositoryTest { }.returns(Either.Right(mlsClient)) } - fun withGettingE2EISettingsReturns(result: Either) = apply { - every { + suspend fun withGettingE2EISettingsReturns(result: Either) = apply { + coEvery { userConfigRepository.getE2EISettings() }.returns(result) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/RevocationListCheckerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/RevocationListCheckerTest.kt index ff2ff4e2b8d..f0c9405ca8f 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/RevocationListCheckerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/e2ei/RevocationListCheckerTest.kt @@ -146,7 +146,7 @@ class RevocationListCheckerTest { userConfigRepository.isMLSEnabled() }.returns(result.right()) - every { + coEvery { userConfigRepository.getE2EISettings() }.returns(E2EISettings(true, DUMMY_URL, DateTimeUtil.currentInstant(), false, null).right()) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/properties/UserPropertyRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/properties/UserPropertyRepositoryTest.kt index 0d47002c349..e9034a41e41 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/properties/UserPropertyRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/properties/UserPropertyRepositoryTest.kt @@ -19,21 +19,19 @@ package com.wire.kalium.logic.data.properties import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.framework.TestUser -import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.util.shouldSucceed -import com.wire.kalium.network.api.base.authenticated.properties.PropertiesApi import com.wire.kalium.network.api.authenticated.properties.PropertyKey +import com.wire.kalium.network.api.base.authenticated.properties.PropertiesApi import com.wire.kalium.network.utils.NetworkResponse import io.mockative.any -import io.mockative.eq import io.mockative.coEvery import io.mockative.coVerify -import io.mockative.every +import io.mockative.eq import io.mockative.mock import io.mockative.once -import io.mockative.verify import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -55,7 +53,7 @@ class UserPropertyRepositoryTest { arrangement.propertiesApi.setProperty(any(), any()) }.wasInvoked(once) - verify { + coVerify { arrangement.userConfigRepository.setReadReceiptsStatus(eq(true)) }.wasInvoked(once) } @@ -74,7 +72,7 @@ class UserPropertyRepositoryTest { arrangement.propertiesApi.deleteProperty(any()) }.wasInvoked(once) - verify { + coVerify { arrangement.userConfigRepository.setReadReceiptsStatus(eq(false)) }.wasInvoked(once) } @@ -88,7 +86,7 @@ class UserPropertyRepositoryTest { val result = repository.getReadReceiptsStatus() assertFalse(result) - verify { + coVerify { arrangement.userConfigRepository.isReadReceiptsEnabled() }.wasInvoked(exactly = once) } @@ -113,14 +111,14 @@ class UserPropertyRepositoryTest { }.returns(NetworkResponse.Success(Unit, mapOf(), 200)) } - fun withUpdateReadReceiptsLocallySuccess() = apply { - every { + suspend fun withUpdateReadReceiptsLocallySuccess() = apply { + coEvery { userConfigRepository.setReadReceiptsStatus(any()) }.returns(Either.Right(Unit)) } - fun withNullReadReceiptsStatus() = apply { - every { + suspend fun withNullReadReceiptsStatus() = apply { + coEvery { userConfigRepository.isReadReceiptsEnabled() }.returns(flowOf(Either.Left(StorageFailure.DataNotFound))) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/team/TeamRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/team/TeamRepositoryTest.kt index f7792ff502a..7086d1a6f0d 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/team/TeamRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/team/TeamRepositoryTest.kt @@ -47,7 +47,7 @@ import com.wire.kalium.persistence.dao.ServiceDAO import com.wire.kalium.persistence.dao.TeamDAO import com.wire.kalium.persistence.dao.TeamEntity import com.wire.kalium.persistence.dao.UserDAO -import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAO import io.mockative.any import io.mockative.coEvery import io.mockative.coVerify diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCaseTest.kt index 896b4ff4aea..bbbbac836b6 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/MarkTeamAppLockStatusAsNotifiedUseCaseTest.kt @@ -17,25 +17,26 @@ */ package com.wire.kalium.logic.feature.applock -import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.common.functional.Either -import io.mockative.every +import com.wire.kalium.logic.configuration.UserConfigRepository +import io.mockative.coEvery +import io.mockative.coVerify import io.mockative.mock import io.mockative.once -import io.mockative.verify +import kotlinx.coroutines.test.runTest import kotlin.test.Test internal class MarkTeamAppLockStatusAsNotifiedUseCaseTest { @Test - fun givenAppLockStatusChanged_whenMarkingAsNotified_thenSetAppLockAsNotified() { + fun givenAppLockStatusChanged_whenMarkingAsNotified_thenSetAppLockAsNotified() = runTest { val (arrangement, useCase) = Arrangement() .withSuccess() .arrange() useCase.invoke() - verify { + coVerify { arrangement.userConfigRepository.setTeamAppLockAsNotified() }.wasInvoked(once) } @@ -48,8 +49,8 @@ internal class MarkTeamAppLockStatusAsNotifiedUseCaseTest { userConfigRepository = userConfigRepository ) - fun withSuccess() = apply { - every { + suspend fun withSuccess() = apply { + coEvery { userConfigRepository.setTeamAppLockAsNotified() }.returns(Either.Right(Unit)) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCaseTest.kt index 22315e51e2a..f60aede22e8 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/IsEligibleToStartCallUseCaseTest.kt @@ -19,14 +19,13 @@ package com.wire.kalium.logic.feature.call.usecase import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.call.CallRepository import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.id.ConversationId -import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.test_util.TestKaliumDispatcher import io.mockative.coEvery -import io.mockative.every import io.mockative.mock import kotlinx.coroutines.test.runTest import kotlin.test.BeforeTest @@ -35,9 +34,9 @@ import kotlin.test.assertEquals internal class IsEligibleToStartCallUseCaseTest { - val userConfigRepository = mock(UserConfigRepository::class) + val userConfigRepository = mock(UserConfigRepository::class) - val callRepository = mock(CallRepository::class) + val callRepository = mock(CallRepository::class) private lateinit var isEligibleToStartCall: IsEligibleToStartCallUseCase @@ -58,7 +57,7 @@ internal class IsEligibleToStartCallUseCaseTest { callRepository.establishedCallConversationId() }.returns(null) - every { + coEvery { userConfigRepository.isConferenceCallingEnabled() }.returns(Either.Left(StorageFailure.Generic(Throwable("error")))) @@ -80,7 +79,7 @@ internal class IsEligibleToStartCallUseCaseTest { callRepository.establishedCallConversationId() }.returns(null) - every { + coEvery { userConfigRepository.isConferenceCallingEnabled() }.returns(Either.Left(StorageFailure.Generic(Throwable("error")))) @@ -102,7 +101,7 @@ internal class IsEligibleToStartCallUseCaseTest { callRepository.establishedCallConversationId() }.returns(establishedCallConversationId) - every { + coEvery { userConfigRepository.isConferenceCallingEnabled() }.returns(Either.Left(StorageFailure.Generic(Throwable("error")))) @@ -124,7 +123,7 @@ internal class IsEligibleToStartCallUseCaseTest { callRepository.establishedCallConversationId() }.returns(establishedCallConversationId) - every { + coEvery { userConfigRepository.isConferenceCallingEnabled() }.returns(Either.Right(true)) @@ -146,7 +145,7 @@ internal class IsEligibleToStartCallUseCaseTest { callRepository.establishedCallConversationId() }.returns(conversationId) - every { + coEvery { userConfigRepository.isConferenceCallingEnabled() }.returns(Either.Right(true)) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/ObserveConferenceCallingEnabledUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/ObserveConferenceCallingEnabledUseCaseTest.kt index 9f2bb4929ee..48f625cd085 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/ObserveConferenceCallingEnabledUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/call/usecase/ObserveConferenceCallingEnabledUseCaseTest.kt @@ -20,6 +20,7 @@ package com.wire.kalium.logic.feature.call.usecase import app.cash.turbine.test import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.common.functional.Either +import io.mockative.coEvery import io.mockative.every import io.mockative.mock import kotlinx.coroutines.flow.asFlow @@ -114,8 +115,8 @@ class ObserveConferenceCallingEnabledUseCaseTest { val userConfigRepository = mock(UserConfigRepository::class) - fun withDefaultValue(values: List) = apply { - every { + suspend fun withDefaultValue(values: List) = apply { + coEvery { userConfigRepository.observeConferenceCallingEnabled() }.returns(values.map { Either.Right(it) }.asFlow()) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/MarkEnablingE2EIAsNotifiedUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/MarkEnablingE2EIAsNotifiedUseCaseTest.kt index eb045e8f936..3f5a91359c3 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/MarkEnablingE2EIAsNotifiedUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/MarkEnablingE2EIAsNotifiedUseCaseTest.kt @@ -17,16 +17,17 @@ */ package com.wire.kalium.logic.feature.client +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.feature.user.MarkEnablingE2EIAsNotifiedUseCase import com.wire.kalium.logic.feature.user.MarkEnablingE2EIAsNotifiedUseCaseImpl -import com.wire.kalium.common.functional.Either import io.mockative.any +import io.mockative.coEvery import io.mockative.coVerify import io.mockative.eq -import io.mockative.every import io.mockative.mock import io.mockative.once +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.time.Duration @@ -96,9 +97,11 @@ class MarkEnablingE2EIAsNotifiedUseCaseTest { val userConfigRepository = mock(UserConfigRepository::class) init { - every { - userConfigRepository.snoozeE2EINotification(any()) - }.returns(Either.Right(Unit)) + runBlocking { + coEvery { + userConfigRepository.snoozeE2EINotification(any()) + }.returns(Either.Right(Unit)) + } } private var markMLSE2EIEnableChangeAsNotified: MarkEnablingE2EIAsNotifiedUseCase = diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/ObserveE2EIRequiredUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/ObserveE2EIRequiredUseCaseTest.kt index 48ca8f6b432..139ca19f64c 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/ObserveE2EIRequiredUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/ObserveE2EIRequiredUseCaseTest.kt @@ -18,15 +18,13 @@ package com.wire.kalium.logic.feature.client import app.cash.turbine.test -import com.wire.kalium.common.error.CoreFailure -import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.E2EISettings import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.conversation.ClientId import com.wire.kalium.logic.data.id.CurrentClientIdProvider import com.wire.kalium.logic.data.id.QualifiedClientID import com.wire.kalium.logic.feature.e2ei.MLSClientE2EIStatus -import com.wire.kalium.logic.feature.e2ei.MLSClientIdentity import com.wire.kalium.logic.feature.e2ei.usecase.GetMLSClientIdentityResult import com.wire.kalium.logic.feature.e2ei.usecase.GetMLSClientIdentityUseCase import com.wire.kalium.logic.feature.user.E2EIRequiredResult @@ -37,14 +35,13 @@ import com.wire.kalium.logic.framework.TestClient import com.wire.kalium.logic.framework.TestMLSClientIdentity.getMLSClientIdentityWithE2EI import com.wire.kalium.logic.framework.TestMLSClientIdentity.getMLSClientIdentityWithOutE2EI import com.wire.kalium.logic.framework.TestUser -import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.test_util.TestKaliumDispatcher import com.wire.kalium.util.DateTimeUtil import io.mockative.any import io.mockative.coEvery +import io.mockative.coVerify import io.mockative.every import io.mockative.mock -import io.mockative.verify import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf @@ -181,7 +178,7 @@ class ObserveE2EIRequiredUseCaseTest { awaitComplete() } - verify { + coVerify { arrangement.userConfigRepository.observeE2EINotificationTime() }.wasNotInvoked() } @@ -317,7 +314,7 @@ class ObserveE2EIRequiredUseCaseTest { } private class Arrangement(testDispatcher: CoroutineDispatcher = UnconfinedTestDispatcher()) { - val userConfigRepository = mock(UserConfigRepository::class) + val userConfigRepository = mock(UserConfigRepository::class) val featureSupport = mock(FeatureSupport::class) val e2eiCertificate = mock(GetMLSClientIdentityUseCase::class) val currentClientIdProvider = mock(CurrentClientIdProvider::class) @@ -330,8 +327,8 @@ class ObserveE2EIRequiredUseCaseTest { .returns(flowOf(Either.Right(setting))) } - fun withE2EINotificationTime(instant: Instant) = apply { - every { userConfigRepository.observeE2EINotificationTime() } + suspend fun withE2EINotificationTime(instant: Instant) = apply { + coEvery { userConfigRepository.observeE2EINotificationTime() } .returns(flowOf(Either.Right(instant))) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt index 4a366fa85ad..f9aa0e6bfdd 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt @@ -161,8 +161,8 @@ class RegisterMLSClientUseCaseTest { val keyPackageLimitsProvider = mock(KeyPackageLimitsProvider::class) val userConfigRepository = mock(UserConfigRepository::class) - fun withGettingE2EISettingsReturns(result: Either) = apply { - every { + suspend fun withGettingE2EISettingsReturns(result: Either) = apply { + coEvery { userConfigRepository.getE2EISettings() }.returns(result) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCaseTest.kt index 94de13a75f0..f50320ab09f 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCaseTest.kt @@ -67,7 +67,7 @@ import com.wire.kalium.logic.util.shouldSucceed import com.wire.kalium.persistence.TestUserDatabase import com.wire.kalium.persistence.config.inMemoryUserConfigStorage import com.wire.kalium.persistence.dao.SupportedProtocolEntity -import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.dao.UserConfigDAO import com.wire.kalium.util.DateTimeUtil import io.mockative.any import io.mockative.coEvery @@ -908,7 +908,7 @@ class SyncFeatureConfigsUseCaseTest { }.returns(result) } - fun withLocalSharingEnabledReturning( + suspend fun withLocalSharingEnabledReturning( status: Boolean, isStatusChanged: Boolean? ) = apply { @@ -918,7 +918,7 @@ class SyncFeatureConfigsUseCaseTest { ) } - fun withGuestRoomLinkEnabledReturning(guestRoomLinkStatus: GuestRoomLinkStatus) = apply { + suspend fun withGuestRoomLinkEnabledReturning(guestRoomLinkStatus: GuestRoomLinkStatus) = apply { inMemoryStorage.persistGuestRoomLinkFeatureFlag( guestRoomLinkStatus.isGuestRoomLinkEnabled ?: false, guestRoomLinkStatus.isStatusChanged diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandlerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandlerTest.kt index 3a5e22d1047..ecefd33ee3c 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandlerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/AppLockConfigHandlerTest.kt @@ -18,24 +18,26 @@ package com.wire.kalium.logic.feature.featureConfig.handler import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.AppLockTeamConfig import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.featureConfig.AppLockModel import com.wire.kalium.logic.data.featureConfig.Status -import com.wire.kalium.common.functional.Either import io.mockative.any +import io.mockative.coEvery +import io.mockative.coVerify import io.mockative.eq -import io.mockative.every import io.mockative.mock import io.mockative.once -import io.mockative.verify +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.time.Duration.Companion.seconds internal class AppLockConfigHandlerTest { @Test - fun givenConfigRepositoryReturnsFailureWithStatusDisabled_whenHandlingTheEvent_ThenSetAppLockWithStatusChangedFalse() { + fun givenConfigRepositoryReturnsFailureWithStatusDisabled_whenHandlingTheEvent_ThenSetAppLockWithStatusChangedFalse() = runTest { val appLockModel = AppLockModel(Status.DISABLED, 20) val (arrangement, appLockConfigHandler) = Arrangement() .withUserConfigRepositoryFailure() @@ -43,11 +45,11 @@ internal class AppLockConfigHandlerTest { appLockConfigHandler.handle(appLockModel) - verify { + coVerify { arrangement.userConfigRepository.isTeamAppLockEnabled() }.wasInvoked(exactly = once) - verify { + coVerify { arrangement.userConfigRepository.setAppLockStatus( eq(appLockModel.status.toBoolean()), eq(appLockModel.inactivityTimeoutSecs), @@ -57,7 +59,7 @@ internal class AppLockConfigHandlerTest { } @Test - fun givenConfigRepositoryReturnsFailureWithStatusEnabled_whenHandlingTheEvent_ThenSetAppLockWithStatusChangedTrue() { + fun givenConfigRepositoryReturnsFailureWithStatusEnabled_whenHandlingTheEvent_ThenSetAppLockWithStatusChangedTrue() = runTest { val appLockModel = AppLockModel(Status.ENABLED, 20) val (arrangement, appLockConfigHandler) = Arrangement() .withUserConfigRepositoryFailure() @@ -65,11 +67,11 @@ internal class AppLockConfigHandlerTest { appLockConfigHandler.handle(appLockModel) - verify { + coVerify { arrangement.userConfigRepository.isTeamAppLockEnabled() }.wasInvoked(exactly = once) - verify { + coVerify { arrangement.userConfigRepository.setAppLockStatus( eq(appLockModel.status.toBoolean()), eq(appLockModel.inactivityTimeoutSecs), @@ -79,7 +81,7 @@ internal class AppLockConfigHandlerTest { } @Test - fun givenNewStatusSameAsCurrent_whenHandlingTheEvent_ThenSetAppLockWithOldStatusChangedValue() { + fun givenNewStatusSameAsCurrent_whenHandlingTheEvent_ThenSetAppLockWithOldStatusChangedValue() = runTest { val appLockModel = AppLockModel(Status.ENABLED, 44) val (arrangement, appLockConfigHandler) = Arrangement() .withAppLocked() @@ -87,11 +89,11 @@ internal class AppLockConfigHandlerTest { appLockConfigHandler.handle(appLockModel) - verify { + coVerify { arrangement.userConfigRepository.isTeamAppLockEnabled() }.wasInvoked(exactly = once) - verify { + coVerify { arrangement.userConfigRepository.setAppLockStatus( eq(appLockModel.status.toBoolean()), eq(appLockModel.inactivityTimeoutSecs), @@ -101,7 +103,7 @@ internal class AppLockConfigHandlerTest { } @Test - fun givenNewStatusDifferentThenCurrent_whenHandlingTheEvent_ThenSetAppLockWithStatusChangedTrue() { + fun givenNewStatusDifferentThenCurrent_whenHandlingTheEvent_ThenSetAppLockWithStatusChangedTrue() = runTest { val appLockModel = AppLockModel(Status.ENABLED, 20) val (arrangement, appLockConfigHandler) = Arrangement() .withAppNotLocked() @@ -109,11 +111,11 @@ internal class AppLockConfigHandlerTest { appLockConfigHandler.handle(appLockModel) - verify { + coVerify { arrangement.userConfigRepository.isTeamAppLockEnabled() }.wasInvoked(exactly = once) - verify { + coVerify { arrangement.userConfigRepository.setAppLockStatus( eq(appLockModel.status.toBoolean()), eq(appLockModel.inactivityTimeoutSecs), @@ -133,25 +135,27 @@ internal class AppLockConfigHandlerTest { } init { - every { - userConfigRepository.setAppLockStatus(any(), any(), any()) - }.returns(Either.Right(Unit)) + runBlocking { + coEvery { + userConfigRepository.setAppLockStatus(any(), any(), any()) + }.returns(Either.Right(Unit)) + } } - fun withUserConfigRepositoryFailure() = apply { - every { + suspend fun withUserConfigRepositoryFailure() = apply { + coEvery { userConfigRepository.isTeamAppLockEnabled() }.returns(Either.Left(StorageFailure.DataNotFound)) } - fun withAppLocked() = apply { - every { + suspend fun withAppLocked() = apply { + coEvery { userConfigRepository.isTeamAppLockEnabled() }.returns(Either.Right(appLockTeamConfigEnabled)) } - fun withAppNotLocked() = apply { - every { + suspend fun withAppNotLocked() = apply { + coEvery { userConfigRepository.isTeamAppLockEnabled() }.returns(Either.Right(appLockTeamConfigDisabled)) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandlerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandlerTest.kt index d9fe746a6cf..2e0f33aa602 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandlerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/ConferenceCallingConfigHandlerTest.kt @@ -18,24 +18,26 @@ package com.wire.kalium.logic.feature.featureConfig.handler import com.wire.kalium.common.error.StorageFailure -import com.wire.kalium.logic.configuration.UserConfigRepository -import com.wire.kalium.logic.data.featureConfig.ConferenceCallingModel -import com.wire.kalium.logic.data.featureConfig.Status import com.wire.kalium.common.functional.Either import com.wire.kalium.common.functional.isLeft import com.wire.kalium.common.functional.isRight +import com.wire.kalium.logic.configuration.UserConfigRepository +import com.wire.kalium.logic.data.featureConfig.ConferenceCallingModel +import com.wire.kalium.logic.data.featureConfig.Status import io.mockative.any -import io.mockative.every +import io.mockative.coEvery +import io.mockative.coVerify import io.mockative.mock import io.mockative.once -import io.mockative.verify +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertTrue class ConferenceCallingConfigHandlerTest { @Test - fun givenUserConfigRepositoryFailureForConferenceCallingEnabled_whenHandlingTheEvent_ThenReturnFailure() { + fun givenUserConfigRepositoryFailureForConferenceCallingEnabled_whenHandlingTheEvent_ThenReturnFailure() = runTest { val conferenceCallingModel = ConferenceCallingModel(Status.ENABLED, false) val (arrangement, conferenceCallingConfigHandler) = Arrangement() .withSetConferenceCallingEnabledFailure() @@ -43,11 +45,11 @@ class ConferenceCallingConfigHandlerTest { val result = conferenceCallingConfigHandler.handle(conferenceCallingModel) - verify { + coVerify { arrangement.userConfigRepository.setConferenceCallingEnabled(conferenceCallingModel.status.toBoolean()) }.wasInvoked(exactly = once) - verify { + coVerify { arrangement.userConfigRepository.setUseSFTForOneOnOneCalls(any()) }.wasNotInvoked() @@ -55,7 +57,7 @@ class ConferenceCallingConfigHandlerTest { } @Test - fun givenUserConfigRepositoryFailureForUseSFTForOneOnOneCalls_whenHandlingTheEvent_ThenReturnFailure() { + fun givenUserConfigRepositoryFailureForUseSFTForOneOnOneCalls_whenHandlingTheEvent_ThenReturnFailure() = runTest { val conferenceCallingModel = ConferenceCallingModel(Status.ENABLED, false) val (arrangement, conferenceCallingConfigHandler) = Arrangement() .withSetConferenceCallingEnabledSuccess() @@ -64,11 +66,11 @@ class ConferenceCallingConfigHandlerTest { val result = conferenceCallingConfigHandler.handle(conferenceCallingModel) - verify { + coVerify { arrangement.userConfigRepository.setConferenceCallingEnabled(conferenceCallingModel.status.toBoolean()) }.wasInvoked(exactly = once) - verify { + coVerify { arrangement.userConfigRepository.setUseSFTForOneOnOneCalls(any()) }.wasInvoked(exactly = once) @@ -76,7 +78,7 @@ class ConferenceCallingConfigHandlerTest { } @Test - fun givenUserConfigRepositorySuccess_whenHandlingTheEvent_ThenReturnUnit() { + fun givenUserConfigRepositorySuccess_whenHandlingTheEvent_ThenReturnUnit() = runTest { val conferenceCallingModel = ConferenceCallingModel(Status.ENABLED, false) val (arrangement, conferenceCallingConfigHandler) = Arrangement() .withSetConferenceCallingEnabledSuccess() @@ -85,11 +87,11 @@ class ConferenceCallingConfigHandlerTest { val result = conferenceCallingConfigHandler.handle(conferenceCallingModel) - verify { + coVerify { arrangement.userConfigRepository.setConferenceCallingEnabled(conferenceCallingModel.status.toBoolean()) }.wasInvoked(exactly = once) - verify { + coVerify { arrangement.userConfigRepository.setUseSFTForOneOnOneCalls(any()) }.wasInvoked(exactly = once) @@ -107,31 +109,34 @@ class ConferenceCallingConfigHandlerTest { } init { - every { - userConfigRepository.setAppLockStatus(any(), any(), any()) - }.returns(Either.Right(Unit)) + runBlocking { + coEvery { + userConfigRepository.setAppLockStatus(any(), any(), any()) + }.returns(Either.Right(Unit)) + } + } - fun withSetConferenceCallingEnabledFailure() = apply { - every { + suspend fun withSetConferenceCallingEnabledFailure() = apply { + coEvery { userConfigRepository.setConferenceCallingEnabled(any()) }.returns(Either.Left(StorageFailure.DataNotFound)) } - fun withSetConferenceCallingEnabledSuccess() = apply { - every { + suspend fun withSetConferenceCallingEnabledSuccess() = apply { + coEvery { userConfigRepository.setConferenceCallingEnabled(any()) }.returns(Either.Right(Unit)) } - fun withSetUseSFTForOneOnOneCallsFailure() = apply { - every { + suspend fun withSetUseSFTForOneOnOneCallsFailure() = apply { + coEvery { userConfigRepository.setUseSFTForOneOnOneCalls(any()) }.returns(Either.Left(StorageFailure.DataNotFound)) } - fun withSetUseSFTForOneOnOneCallsSuccess() = apply { - every { + suspend fun withSetUseSFTForOneOnOneCallsSuccess() = apply { + coEvery { userConfigRepository.setUseSFTForOneOnOneCalls(any()) }.returns(Either.Right(Unit)) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigrationWorkerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigrationWorkerTest.kt index ae645d992f6..22307b6e36f 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigrationWorkerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigrationWorkerTest.kt @@ -253,9 +253,9 @@ class MLSMigrationWorkerTest { init { runBlocking { coEvery { featureConfigRepository.getFeatureConfigs() }.returns(FeatureConfigTest.newModel().right()) - every { userConfigRepository.setMLSEnabled(any()) }.returns(Unit.right()) + coEvery { userConfigRepository.setMLSEnabled(any()) }.returns(Unit.right()) coEvery { userConfigRepository.getSupportedProtocols() }.returns(NOT_FOUND_FAILURE) - every { userConfigRepository.setDefaultProtocol(any()) }.returns(Unit.right()) + coEvery { userConfigRepository.setDefaultProtocol(any()) }.returns(Unit.right()) coEvery { userConfigRepository.setSupportedProtocols(any>()) }.returns(Unit.right()) coEvery { userConfigRepository.setSupportedCipherSuite(any()) }.returns(Unit.right()) coEvery { userConfigRepository.setMigrationConfiguration(any()) }.returns(Unit.right()) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/search/IsFederationSearchAllowedUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/search/IsFederationSearchAllowedUseCaseTest.kt index cf3daa6ab7a..a3aaeffed93 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/search/IsFederationSearchAllowedUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/search/IsFederationSearchAllowedUseCaseTest.kt @@ -18,6 +18,7 @@ package com.wire.kalium.logic.feature.search import com.wire.kalium.common.error.CoreFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.data.mls.MLSPublicKeys import com.wire.kalium.logic.data.mlspublickeys.MLSPublicKeysRepository import com.wire.kalium.logic.data.user.SupportedProtocol @@ -25,12 +26,10 @@ import com.wire.kalium.logic.feature.conversation.GetConversationProtocolInfoUse import com.wire.kalium.logic.feature.user.GetDefaultProtocolUseCase import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.framework.TestConversation.PROTEUS_PROTOCOL_INFO -import com.wire.kalium.common.functional.Either import com.wire.kalium.util.KaliumDispatcherImpl import io.mockative.any import io.mockative.coEvery import io.mockative.coVerify -import io.mockative.every import io.mockative.mock import io.mockative.once import kotlinx.coroutines.test.runTest @@ -126,8 +125,8 @@ class IsFederationSearchAllowedUseCaseTest { ) ) - fun withDefaultProtocol(protocol: SupportedProtocol) = apply { - every { getDefaultProtocol.invoke() }.returns(protocol) + suspend fun withDefaultProtocol(protocol: SupportedProtocol) = apply { + coEvery { getDefaultProtocol.invoke() }.returns(protocol) } suspend fun withConversationProtocolInfo(protocolInfo: GetConversationProtocolInfoUseCase.Result) = apply { diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/session/IsFileSharingEnabledUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/session/IsFileSharingEnabledUseCaseTest.kt index 2486d74f8b6..4df84c578ca 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/session/IsFileSharingEnabledUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/session/IsFileSharingEnabledUseCaseTest.kt @@ -19,14 +19,14 @@ package com.wire.kalium.logic.feature.session import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.FileSharingStatus import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.feature.user.IsFileSharingEnabledUseCaseImpl -import com.wire.kalium.common.functional.Either -import io.mockative.every +import io.mockative.coEvery +import io.mockative.coVerify import io.mockative.mock import io.mockative.once -import io.mockative.verify import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals @@ -44,7 +44,7 @@ class IsFileSharingEnabledUseCaseTest { val actual = isFileSharingEnabledUseCase.invoke() assertEquals(expectedValue, actual) - verify { + coVerify { arrangement.userConfigRepository.isFileSharingEnabled() }.wasInvoked(exactly = once) } @@ -60,7 +60,7 @@ class IsFileSharingEnabledUseCaseTest { // When isFileSharingEnabledUseCase.invoke() - verify { + coVerify { arrangement.userConfigRepository.isFileSharingEnabled() }.wasInvoked(exactly = once) } @@ -71,16 +71,16 @@ class IsFileSharingEnabledUseCaseTest { val isFileSharingEnabledUseCase = IsFileSharingEnabledUseCaseImpl(userConfigRepository) - fun withSuccessfulResponse(expectedValue: FileSharingStatus): Arrangement { - every { + suspend fun withSuccessfulResponse(expectedValue: FileSharingStatus): Arrangement { + coEvery { userConfigRepository.isFileSharingEnabled() }.returns(Either.Right(expectedValue)) return this } - fun withIsFileSharingEnabledErrorResponse(storageFailure: StorageFailure): Arrangement { - every { + suspend fun withIsFileSharingEnabledErrorResponse(storageFailure: StorageFailure): Arrangement { + coEvery { userConfigRepository.isFileSharingEnabled() }.returns(Either.Left(storageFailure)) return this diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCaseTest.kt index fc14ac4c5ec..ee75a0c7aa9 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/GetDefaultProtocolUseCaseTest.kt @@ -18,10 +18,10 @@ package com.wire.kalium.logic.feature.user import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.user.SupportedProtocol -import com.wire.kalium.common.functional.Either -import io.mockative.every +import io.mockative.coEvery import io.mockative.mock import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -79,20 +79,20 @@ class GetDefaultProtocolUseCaseTest { userConfigRepository = userConfigRepository ) - fun withReturningSuccessProteusProtocol() = apply { - every { + suspend fun withReturningSuccessProteusProtocol() = apply { + coEvery { userConfigRepository.getDefaultProtocol() }.returns(Either.Right(SupportedProtocol.PROTEUS)) } - fun withReturningSuccessMLSProtocol() = apply { - every { + suspend fun withReturningSuccessMLSProtocol() = apply { + coEvery { userConfigRepository.getDefaultProtocol() }.returns(Either.Right(SupportedProtocol.MLS)) } - fun withReturningError() = apply { - every { + suspend fun withReturningError() = apply { + coEvery { userConfigRepository.getDefaultProtocol() }.returns(Either.Left(StorageFailure.Generic(Throwable()))) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCaseTest.kt index 5df96313ab8..dc08e598040 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/user/guestroomlink/MarkGuestLinkFeatureFlagAsNotChangedUseCaseTest.kt @@ -19,15 +19,16 @@ package com.wire.kalium.logic.feature.user.guestroomlink import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.GuestRoomLinkStatus import com.wire.kalium.logic.configuration.UserConfigRepository -import com.wire.kalium.common.functional.Either import io.mockative.any +import io.mockative.coEvery +import io.mockative.coVerify import io.mockative.eq -import io.mockative.every import io.mockative.mock import io.mockative.once -import io.mockative.verify +import kotlinx.coroutines.test.runTest import kotlin.test.BeforeTest import kotlin.test.Test @@ -43,37 +44,37 @@ internal class MarkGuestLinkFeatureFlagAsNotChangedUseCaseTest { } @Test - fun givenRepositoryReturnsFailure_whenInvokingUseCase_thenDoNotUpdateGuestStatus() { - every { + fun givenRepositoryReturnsFailure_whenInvokingUseCase_thenDoNotUpdateGuestStatus() = runTest { + coEvery { userConfigRepository.getGuestRoomLinkStatus() }.returns(Either.Left(StorageFailure.DataNotFound)) markGuestLinkFeatureFlagAsNotChanged() - verify { + coVerify { userConfigRepository.getGuestRoomLinkStatus() }.wasInvoked(exactly = once) - verify { + coVerify { userConfigRepository.setGuestRoomStatus(any(), eq(false)) }.wasNotInvoked() } @Test - fun givenRepositoryReturnsSuccess_whenInvokingUseCase_thenUpdateGuestStatus() { - every { + fun givenRepositoryReturnsSuccess_whenInvokingUseCase_thenUpdateGuestStatus() = runTest { + coEvery { userConfigRepository.getGuestRoomLinkStatus() }.returns(Either.Right(GuestRoomLinkStatus(isGuestRoomLinkEnabled = true, isStatusChanged = false))) - every { + coEvery { userConfigRepository.setGuestRoomStatus(status = false, isStatusChanged = false) }.returns(Either.Right(Unit)) markGuestLinkFeatureFlagAsNotChanged() - verify { + coVerify { userConfigRepository.getGuestRoomLinkStatus() }.wasInvoked(exactly = once) - verify { + coVerify { userConfigRepository.setGuestRoomStatus(any(), eq(false)) }.wasInvoked(once) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiverTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiverTest.kt index 95f794ff02e..1133ff1746a 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiverTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiverTest.kt @@ -53,11 +53,9 @@ import io.mockative.any import io.mockative.coEvery import io.mockative.coVerify import io.mockative.eq -import io.mockative.every import io.mockative.matches import io.mockative.mock import io.mockative.once -import io.mockative.verify import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -79,7 +77,7 @@ class FeatureConfigEventReceiverTest { deliveryInfo = TestEvent.liveDeliveryInfo ) - verify { + coVerify { arrangement.userConfigRepository.setFileSharingStatus(eq(true), eq(true)) }.wasInvoked(once) } @@ -97,7 +95,7 @@ class FeatureConfigEventReceiverTest { deliveryInfo = TestEvent.liveDeliveryInfo ) - verify { + coVerify { arrangement.userConfigRepository.setFileSharingStatus(eq(false), eq(true)) }.wasInvoked(once) } @@ -115,7 +113,7 @@ class FeatureConfigEventReceiverTest { deliveryInfo = TestEvent.liveDeliveryInfo ) - verify { + coVerify { arrangement.userConfigRepository.setFileSharingStatus(eq(false), eq(false)) }.wasInvoked(once) } @@ -133,11 +131,11 @@ class FeatureConfigEventReceiverTest { TestEvent.liveDeliveryInfo ) - verify { + coVerify { arrangement.userConfigRepository.setConferenceCallingEnabled(eq(true)) }.wasInvoked(once) - verify { + coVerify { arrangement.userConfigRepository.setUseSFTForOneOnOneCalls(eq(false)) }.wasInvoked(once) } @@ -155,11 +153,11 @@ class FeatureConfigEventReceiverTest { deliveryInfo = TestEvent.liveDeliveryInfo ) - verify { + coVerify { arrangement.userConfigRepository.setConferenceCallingEnabled(eq(false)) }.wasInvoked(once) - verify { + coVerify { arrangement.userConfigRepository.setUseSFTForOneOnOneCalls(eq(true)) }.wasNotInvoked() } @@ -359,26 +357,26 @@ class FeatureConfigEventReceiverTest { ) } - fun withSettingFileSharingEnabledSuccessful() = apply { - every { + suspend fun withSettingFileSharingEnabledSuccessful() = apply { + coEvery { userConfigRepository.setFileSharingStatus(any(), any()) }.returns(Either.Right(Unit)) } - fun withSettingConferenceCallingEnabledSuccessful() = apply { - every { + suspend fun withSettingConferenceCallingEnabledSuccessful() = apply { + coEvery { userConfigRepository.setConferenceCallingEnabled(any()) }.returns(Either.Right(Unit)) } - fun withSetUseSFTForOneOnOneCallsSuccessful() = apply { - every { + suspend fun withSetUseSFTForOneOnOneCallsSuccessful() = apply { + coEvery { userConfigRepository.setUseSFTForOneOnOneCalls(any()) }.returns(Either.Right(Unit)) } - fun withIsFileSharingEnabled(result: Either) = apply { - every { + suspend fun withIsFileSharingEnabled(result: Either) = apply { + coEvery { userConfigRepository.isFileSharingEnabled() }.returns(result) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiverTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiverTest.kt index 609b90038de..f1fc1894b7a 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiverTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/UserPropertiesEventReceiverTest.kt @@ -46,7 +46,7 @@ class UserPropertiesEventReceiverTest { eventReceiver.onEvent(arrangement.transactionContext, event, TestEvent.liveDeliveryInfo) - verify { + coVerify { arrangement.userConfigRepository.setReadReceiptsStatus(any()) }.wasInvoked(exactly = once) } @@ -75,8 +75,8 @@ class UserPropertiesEventReceiverTest { conversationFolderRepository = conversationFolderRepository ) - fun withUpdateReadReceiptsSuccess() = apply { - every { + suspend fun withUpdateReadReceiptsSuccess() = apply { + coEvery { userConfigRepository.setReadReceiptsStatus(any()) }.returns(Either.Right(Unit)) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/conversation/message/ApplicationMessageHandlerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/conversation/message/ApplicationMessageHandlerTest.kt index 944042be407..cbd12558621 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/conversation/message/ApplicationMessageHandlerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/receiver/conversation/message/ApplicationMessageHandlerTest.kt @@ -373,8 +373,8 @@ class ApplicationMessageHandlerTest { }.returns(result) } - fun withFileSharingEnabled() = apply { - every { + suspend fun withFileSharingEnabled() = apply { + coEvery { userConfigRepository.isFileSharingEnabled() }.returns( Either.Right( diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt index d16fe793687..aadfdb7baee 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt @@ -18,15 +18,14 @@ package com.wire.kalium.logic.util.arrangement.repository import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either +import com.wire.kalium.common.functional.right import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.featureConfig.MLSMigrationModel import com.wire.kalium.logic.data.mls.SupportedCipherSuite import com.wire.kalium.logic.data.user.SupportedProtocol -import com.wire.kalium.common.functional.Either -import com.wire.kalium.common.functional.right import io.mockative.any import io.mockative.coEvery -import io.mockative.every import io.mockative.mock import kotlinx.coroutines.flow.flowOf @@ -35,9 +34,9 @@ internal interface UserConfigRepositoryArrangement { suspend fun withGetSupportedProtocolsReturning(result: Either>) suspend fun withSetSupportedProtocolsSuccessful() - fun withSetDefaultProtocolSuccessful() - fun withGetDefaultProtocolReturning(result: Either) - fun withSetMLSEnabledSuccessful() + suspend fun withSetDefaultProtocolSuccessful() + suspend fun withGetDefaultProtocolReturning(result: Either) + suspend fun withSetMLSEnabledSuccessful() suspend fun withGetMLSEnabledReturning(result: Either) suspend fun withSetMigrationConfigurationSuccessful() suspend fun withGetMigrationConfigurationReturning(result: Either) @@ -70,18 +69,18 @@ internal class UserConfigRepositoryArrangementImpl : UserConfigRepositoryArrange }.returns(Either.Right(Unit)) } - override fun withSetDefaultProtocolSuccessful() { - every { + override suspend fun withSetDefaultProtocolSuccessful() { + coEvery { userConfigRepository.setDefaultProtocol(any()) }.returns(Either.Right(Unit)) } - override fun withGetDefaultProtocolReturning(result: Either) { - every { userConfigRepository.getDefaultProtocol() }.returns(result) + override suspend fun withGetDefaultProtocolReturning(result: Either) { + coEvery { userConfigRepository.getDefaultProtocol() }.returns(result) } - override fun withSetMLSEnabledSuccessful() { - every { + override suspend fun withSetMLSEnabledSuccessful() { + coEvery { userConfigRepository.setMLSEnabled(any()) }.returns(Either.Right(Unit)) } @@ -145,6 +144,6 @@ internal class UserConfigRepositoryArrangementImpl : UserConfigRepositoryArrange } override suspend fun withConferenceCallingEnabled(result: Boolean) { - every { userConfigRepository.isConferenceCallingEnabled() }.returns(result.right()) + coEvery { userConfigRepository.isConferenceCallingEnabled() }.returns(result.right()) } } diff --git a/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt b/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt index f6ba3c9e011..240b79c6e06 100644 --- a/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt +++ b/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt @@ -18,6 +18,7 @@ package com.wire.kalium.logic.sync.receiver.asset import com.wire.kalium.common.error.StorageFailure +import com.wire.kalium.common.functional.Either import com.wire.kalium.logic.configuration.FileSharingStatus import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.conversation.ClientId @@ -32,7 +33,6 @@ import com.wire.kalium.logic.data.message.hasValidData import com.wire.kalium.logic.data.message.hasValidRemoteData import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.feature.asset.ValidateAssetFileTypeUseCase -import com.wire.kalium.common.functional.Either import com.wire.kalium.util.time.UNIX_FIRST_DATE import io.mockative.any import io.mockative.coEvery @@ -476,8 +476,8 @@ class AssetMessageHandlerTest { }.returns(result) } - fun withSuccessfulFileSharingFlag(value: FileSharingStatus.Value) = apply { - every { + suspend fun withSuccessfulFileSharingFlag(value: FileSharingStatus.Value) = apply { + coEvery { userConfigRepository.isFileSharingEnabled() }.returns(Either.Right(FileSharingStatus(state = value, isStatusChanged = false))) } From 053b80a8384dcbf41f7ab30265801730e13b1dc6 Mon Sep 17 00:00:00 2001 From: Yamil Medina Date: Tue, 3 Feb 2026 09:56:34 +0100 Subject: [PATCH 2/4] refactor: provide migration of data from shared prefs to dao with slow sync migration mechanism - pt2 (WPB-23210) (#3833) * refactor: implement userprefs dao as replacements of user configs impl. * add test * add test * refactor: change to enums for a way to wrap all the configs * refactor: execute migration of local props and increase slow sync to have updated * fix detekt * fix detekt --- .../config/TestUserConfigStorage.kt | 164 ++++++++++++++++++ .../kmmSettings/UserPrefBuilder.kt | 5 + .../kmmSettings/UserPrefBuilder.kt | 5 + .../persistence/config/UserConfigStorage.kt | 135 +++++++------- .../kalium/persistence/dao/UserPrefsDAO.kt | 112 ++++++------ .../kmmSettings/UserPrefBuilder.kt | 5 + .../kmmSettings/UserPrefBuilder.kt | 5 + .../kmmSettings/UserPrefBuilder.kt | 5 + .../kalium/logic/feature/UserSessionScope.kt | 7 +- .../kalium/logic/sync/slow/SlowSyncManager.kt | 2 +- .../migration/SyncMigrationStepsProvider.kt | 9 +- .../steps/SyncMigrationStep_10_11.kt | 70 ++++++++ .../SyncMigrationStepsProviderTest.kt | 18 +- 13 files changed, 420 insertions(+), 122 deletions(-) create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt diff --git a/data/persistence-test/src/commonMain/kotlin/com/wire/kalium/persistence/config/TestUserConfigStorage.kt b/data/persistence-test/src/commonMain/kotlin/com/wire/kalium/persistence/config/TestUserConfigStorage.kt index e3a0d54d5cb..d7485a29f89 100644 --- a/data/persistence-test/src/commonMain/kotlin/com/wire/kalium/persistence/config/TestUserConfigStorage.kt +++ b/data/persistence-test/src/commonMain/kotlin/com/wire/kalium/persistence/config/TestUserConfigStorage.kt @@ -18,8 +18,172 @@ package com.wire.kalium.persistence.config import com.russhwolf.settings.MapSettings +import com.wire.kalium.persistence.dao.SupportedProtocolEntity import com.wire.kalium.persistence.kmmSettings.KaliumPreferencesSettings +import kotlinx.coroutines.flow.Flow fun inMemoryUserConfigStorage(): UserConfigStorage = UserConfigStorageImpl( KaliumPreferencesSettings(MapSettings()) ) + +@Suppress("TooManyFunctions") +class FakeUserConfigStorage( + val backingStorage: MutableMap = mutableMapOf() +) : UserConfigStorage { + override suspend fun persistAppLockStatus( + isEnforced: Boolean, + inactivityTimeoutSecs: Int, + isStatusChanged: Boolean? + ) { + backingStorage["appLockStatus"] = AppLockConfigEntity( + inactivityTimeoutSecs = 60, + enforceAppLock = true, + isStatusChanged = false, + ) + } + + override suspend fun appLockStatus(): AppLockConfigEntity? { + return backingStorage["appLockStatus"] as? AppLockConfigEntity + } + + override fun appLockFlow(): Flow { + throw NotImplementedError() + } + + override suspend fun setTeamAppLockAsNotified() { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistFileSharingStatus(status: Boolean, isStatusChanged: Boolean?) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isFileSharingEnabled(): IsFileSharingEnabledEntity? { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override fun isFileSharingEnabledFlow(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun setFileSharingAsNotified() { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override fun isClassifiedDomainsEnabledFlow(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isSecondFactorPasswordChallengeRequired(): Boolean { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistDefaultProtocol(protocol: SupportedProtocolEntity) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun defaultProtocol(): SupportedProtocolEntity { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun enableMLS(enabled: Boolean) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isMLSEnabled(): Boolean { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun setE2EISettings(settingEntity: E2EISettingsEntity?) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun getE2EISettings(): E2EISettingsEntity? { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override fun e2EISettingsFlow(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistConferenceCalling(enabled: Boolean) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isConferenceCallingEnabled(): Boolean { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isConferenceCallingEnabledFlow(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun shouldUseSftForOneOnOneCalls(): Boolean { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun areReadReceiptsEnabled(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistReadReceipts(enabled: Boolean) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isTypingIndicatorEnabled(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistTypingIndicator(enabled: Boolean) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistGuestRoomLinkFeatureFlag(status: Boolean, isStatusChanged: Boolean?) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override fun isGuestRoomLinkEnabledFlow(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun isScreenshotCensoringEnabledFlow(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun persistScreenshotCensoring(enabled: Boolean) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun setIfAbsentE2EINotificationTime(timeStamp: Long) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun getE2EINotificationTime(): Long? { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun e2EINotificationTimeFlow(): Flow { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + + override suspend fun updateE2EINotificationTime(timeStamp: Long) { + throw NotImplementedError("Implement your fake logic if needed using the map provided.") + } + +} diff --git a/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt index 282d2e4eacb..bf803f1c05e 100644 --- a/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ b/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt @@ -25,6 +25,11 @@ import com.wire.kalium.persistence.config.UserConfigStorage import com.wire.kalium.persistence.config.UserConfigStorageImpl import com.wire.kalium.persistence.dao.UserIDEntity +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) actual class UserPrefBuilder( userId: UserIDEntity, context: Context, diff --git a/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt index 2adbf3aac22..46a4f8d9ad9 100644 --- a/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ b/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt @@ -24,6 +24,11 @@ import com.wire.kalium.persistence.config.UserConfigStorage import com.wire.kalium.persistence.config.UserConfigStorageImpl import com.wire.kalium.persistence.dao.UserIDEntity +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) actual class UserPrefBuilder constructor( userId: UserIDEntity, rootPath: String, diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt index 6d1693553da..808e39c9f61 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt @@ -18,6 +18,22 @@ package com.wire.kalium.persistence.config +import com.wire.kalium.persistence.config.UserConfigStorage.Companion.DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE +import com.wire.kalium.persistence.config.UserConfigStorage.Companion.DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.APP_LOCK +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.DEFAULT_PROTOCOL +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.E2EI_NOTIFICATION_TIME +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.E2EI_SETTINGS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_CLASSIFIED_DOMAINS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_CONFERENCE_CALLING +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_MLS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_READ_RECEIPTS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_SCREENSHOT_CENSORING +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_TYPING_INDICATOR +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.FILE_SHARING +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.GUEST_ROOM_LINK +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.USE_SFT_FOR_ONE_ON_ONE_CALLS import com.wire.kalium.persistence.dao.SupportedProtocolEntity import com.wire.kalium.persistence.kmmSettings.KaliumPreferences import com.wire.kalium.util.time.Second @@ -183,6 +199,28 @@ interface UserConfigStorage { suspend fun getE2EINotificationTime(): Long? suspend fun e2EINotificationTimeFlow(): Flow suspend fun updateE2EINotificationTime(timeStamp: Long) + + enum class UserPreferences(val key: String) { + FILE_SHARING("file_sharing"), + GUEST_ROOM_LINK("guest_room_link"), + ENABLE_CLASSIFIED_DOMAINS("enable_classified_domains"), + ENABLE_MLS("enable_mls"), + E2EI_SETTINGS("end_to_end_identity_settings"), + E2EI_NOTIFICATION_TIME("end_to_end_identity_notification_time"), + ENABLE_CONFERENCE_CALLING("enable_conference_calling"), + USE_SFT_FOR_ONE_ON_ONE_CALLS("use_sft_for_one_on_one_calls"), + ENABLE_READ_RECEIPTS("enable_read_receipts"), + REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE("require_second_factor_password_challenge"), + ENABLE_SCREENSHOT_CENSORING("enable_screenshot_censoring"), + ENABLE_TYPING_INDICATOR("enable_typing_indicator"), + APP_LOCK("app_lock"), + DEFAULT_PROTOCOL("default_protocol") + } + + companion object { + const val DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE = false + const val DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE = false + } } @Serializable @@ -278,6 +316,7 @@ data class WireCellsConfigEntity( @Serializable val teamQuotaBytes: Long?, ) +@Deprecated("Use UserPrefsDAO instead. This will be removed in future versions.", ReplaceWith("UserPrefsDAO")) @Suppress("TooManyFunctions") class UserConfigStorageImpl constructor( private val kaliumPreferences: KaliumPreferences @@ -355,7 +394,7 @@ class UserConfigStorageImpl constructor( isStatusChanged: Boolean? ) { kaliumPreferences.putSerializable( - APP_LOCK, + APP_LOCK.key, AppLockConfigEntity(inactivityTimeoutSecs, isEnforced, isStatusChanged), AppLockConfigEntity.serializer(), ).also { @@ -365,11 +404,11 @@ class UserConfigStorageImpl constructor( override suspend fun setTeamAppLockAsNotified() { val newValue = - kaliumPreferences.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + kaliumPreferences.getSerializable(APP_LOCK.key, AppLockConfigEntity.serializer()) ?.copy(isStatusChanged = false) ?: return kaliumPreferences.putSerializable( - APP_LOCK, + APP_LOCK.key, newValue, AppLockConfigEntity.serializer() ).also { @@ -378,7 +417,7 @@ class UserConfigStorageImpl constructor( } override suspend fun appLockStatus(): AppLockConfigEntity? = - kaliumPreferences.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + kaliumPreferences.getSerializable(APP_LOCK.key, AppLockConfigEntity.serializer()) override fun appLockFlow(): Flow = appLockFlow.map { appLockStatus() @@ -391,7 +430,7 @@ class UserConfigStorageImpl constructor( isStatusChanged: Boolean? ) { kaliumPreferences.putSerializable( - FILE_SHARING, + FILE_SHARING.key, IsFileSharingEnabledEntity(status, isStatusChanged), IsFileSharingEnabledEntity.serializer() ).also { @@ -400,7 +439,7 @@ class UserConfigStorageImpl constructor( } override suspend fun isFileSharingEnabled(): IsFileSharingEnabledEntity? = - kaliumPreferences.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + kaliumPreferences.getSerializable(FILE_SHARING.key, IsFileSharingEnabledEntity.serializer()) override fun isFileSharingEnabledFlow(): Flow = isFileSharingEnabledFlow @@ -410,11 +449,11 @@ class UserConfigStorageImpl constructor( override suspend fun setFileSharingAsNotified() { val newValue = - kaliumPreferences.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + kaliumPreferences.getSerializable(FILE_SHARING.key, IsFileSharingEnabledEntity.serializer()) ?.copy(isStatusChanged = false) ?: return kaliumPreferences.putSerializable( - FILE_SHARING, + FILE_SHARING.key, newValue, IsFileSharingEnabledEntity.serializer() ).also { @@ -426,13 +465,13 @@ class UserConfigStorageImpl constructor( return isClassifiedDomainsEnabledFlow .map { kaliumPreferences.getSerializable( - ENABLE_CLASSIFIED_DOMAINS, + ENABLE_CLASSIFIED_DOMAINS.key, ClassifiedDomainsEntity.serializer() )!! }.onStart { emit( kaliumPreferences.getSerializable( - ENABLE_CLASSIFIED_DOMAINS, + ENABLE_CLASSIFIED_DOMAINS.key, ClassifiedDomainsEntity.serializer() )!! ) @@ -441,7 +480,7 @@ class UserConfigStorageImpl constructor( override suspend fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) { kaliumPreferences.putSerializable( - ENABLE_CLASSIFIED_DOMAINS, + ENABLE_CLASSIFIED_DOMAINS.key, ClassifiedDomainsEntity(status, classifiedDomains), ClassifiedDomainsEntity.serializer() ).also { @@ -450,32 +489,32 @@ class UserConfigStorageImpl constructor( } override suspend fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) { - kaliumPreferences.putBoolean(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE, isRequired) + kaliumPreferences.putBoolean(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE.key, isRequired) } override suspend fun isSecondFactorPasswordChallengeRequired(): Boolean = - kaliumPreferences.getBoolean(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE, false) + kaliumPreferences.getBoolean(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE.key, false) override suspend fun persistDefaultProtocol(protocol: SupportedProtocolEntity) { - kaliumPreferences.putString(DEFAULT_PROTOCOL, protocol.name) + kaliumPreferences.putString(DEFAULT_PROTOCOL.key, protocol.name) } override suspend fun defaultProtocol(): SupportedProtocolEntity = - kaliumPreferences.getString(DEFAULT_PROTOCOL)?.let { SupportedProtocolEntity.valueOf(it) } + kaliumPreferences.getString(DEFAULT_PROTOCOL.key)?.let { SupportedProtocolEntity.valueOf(it) } ?: SupportedProtocolEntity.PROTEUS override suspend fun enableMLS(enabled: Boolean) { - kaliumPreferences.putBoolean(ENABLE_MLS, enabled) + kaliumPreferences.putBoolean(ENABLE_MLS.key, enabled) } - override suspend fun isMLSEnabled(): Boolean = kaliumPreferences.getBoolean(ENABLE_MLS, false) + override suspend fun isMLSEnabled(): Boolean = kaliumPreferences.getBoolean(ENABLE_MLS.key, false) override suspend fun setE2EISettings(settingEntity: E2EISettingsEntity?) { if (settingEntity == null) { - kaliumPreferences.remove(E2EI_SETTINGS) + kaliumPreferences.remove(E2EI_SETTINGS.key) } else { kaliumPreferences.putSerializable( - E2EI_SETTINGS, + E2EI_SETTINGS.key, settingEntity, E2EISettingsEntity.serializer() ).also { @@ -485,7 +524,7 @@ class UserConfigStorageImpl constructor( } override suspend fun getE2EISettings(): E2EISettingsEntity? { - return kaliumPreferences.getSerializable(E2EI_SETTINGS, E2EISettingsEntity.serializer()) + return kaliumPreferences.getSerializable(E2EI_SETTINGS.key, E2EISettingsEntity.serializer()) } override fun e2EISettingsFlow(): Flow = e2EIFlow @@ -496,16 +535,16 @@ class UserConfigStorageImpl constructor( override suspend fun setIfAbsentE2EINotificationTime(timeStamp: Long) { getE2EINotificationTime().let { current -> if (current == null || current <= 0) - kaliumPreferences.putLong(E2EI_NOTIFICATION_TIME, timeStamp).also { e2EINotificationFlow.tryEmit(Unit) } + kaliumPreferences.putLong(E2EI_NOTIFICATION_TIME.key, timeStamp).also { e2EINotificationFlow.tryEmit(Unit) } } } override suspend fun updateE2EINotificationTime(timeStamp: Long) { - kaliumPreferences.putLong(E2EI_NOTIFICATION_TIME, timeStamp).also { e2EINotificationFlow.tryEmit(Unit) } + kaliumPreferences.putLong(E2EI_NOTIFICATION_TIME.key, timeStamp).also { e2EINotificationFlow.tryEmit(Unit) } } override suspend fun getE2EINotificationTime(): Long? { - return kaliumPreferences.getLong(E2EI_NOTIFICATION_TIME) + return kaliumPreferences.getLong(E2EI_NOTIFICATION_TIME.key) } override suspend fun e2EINotificationTimeFlow(): Flow = e2EINotificationFlow @@ -514,13 +553,13 @@ class UserConfigStorageImpl constructor( .distinctUntilChanged() override suspend fun persistConferenceCalling(enabled: Boolean) { - kaliumPreferences.putBoolean(ENABLE_CONFERENCE_CALLING, enabled) + kaliumPreferences.putBoolean(ENABLE_CONFERENCE_CALLING.key, enabled) conferenceCallingEnabledFlow.tryEmit(Unit) } override suspend fun isConferenceCallingEnabled(): Boolean = kaliumPreferences.getBoolean( - ENABLE_CONFERENCE_CALLING, + ENABLE_CONFERENCE_CALLING.key, DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE ) @@ -529,33 +568,33 @@ class UserConfigStorageImpl constructor( .onStart { emit(isConferenceCallingEnabled()) } override suspend fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) { - kaliumPreferences.putBoolean(USE_SFT_FOR_ONE_ON_ONE_CALLS, shouldUse) + kaliumPreferences.putBoolean(USE_SFT_FOR_ONE_ON_ONE_CALLS.key, shouldUse) } override suspend fun shouldUseSftForOneOnOneCalls(): Boolean = kaliumPreferences.getBoolean( - USE_SFT_FOR_ONE_ON_ONE_CALLS, + USE_SFT_FOR_ONE_ON_ONE_CALLS.key, DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE ) override suspend fun areReadReceiptsEnabled(): Flow = areReadReceiptsEnabledFlow - .map { kaliumPreferences.getBoolean(ENABLE_READ_RECEIPTS, true) } - .onStart { emit(kaliumPreferences.getBoolean(ENABLE_READ_RECEIPTS, true)) } + .map { kaliumPreferences.getBoolean(ENABLE_READ_RECEIPTS.key, true) } + .onStart { emit(kaliumPreferences.getBoolean(ENABLE_READ_RECEIPTS.key, true)) } .distinctUntilChanged() override suspend fun persistReadReceipts(enabled: Boolean) { - kaliumPreferences.putBoolean(ENABLE_READ_RECEIPTS, enabled).also { + kaliumPreferences.putBoolean(ENABLE_READ_RECEIPTS.key, enabled).also { areReadReceiptsEnabledFlow.tryEmit(Unit) } } override suspend fun isTypingIndicatorEnabled(): Flow = isTypingIndicatorEnabledFlow - .map { kaliumPreferences.getBoolean(ENABLE_TYPING_INDICATOR, true) } - .onStart { emit(kaliumPreferences.getBoolean(ENABLE_TYPING_INDICATOR, true)) } + .map { kaliumPreferences.getBoolean(ENABLE_TYPING_INDICATOR.key, true) } + .onStart { emit(kaliumPreferences.getBoolean(ENABLE_TYPING_INDICATOR.key, true)) } .distinctUntilChanged() override suspend fun persistTypingIndicator(enabled: Boolean) { - kaliumPreferences.putBoolean(ENABLE_TYPING_INDICATOR, enabled).also { + kaliumPreferences.putBoolean(ENABLE_TYPING_INDICATOR.key, enabled).also { isTypingIndicatorEnabledFlow.tryEmit(Unit) } } @@ -565,7 +604,7 @@ class UserConfigStorageImpl constructor( isStatusChanged: Boolean? ) { kaliumPreferences.putSerializable( - GUEST_ROOM_LINK, + GUEST_ROOM_LINK.key, IsGuestRoomLinkEnabledEntity(status, isStatusChanged), IsGuestRoomLinkEnabledEntity.serializer() ).also { @@ -575,7 +614,7 @@ class UserConfigStorageImpl constructor( override suspend fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? = kaliumPreferences.getSerializable( - GUEST_ROOM_LINK, + GUEST_ROOM_LINK.key, IsGuestRoomLinkEnabledEntity.serializer() ) @@ -587,33 +626,13 @@ class UserConfigStorageImpl constructor( override suspend fun isScreenshotCensoringEnabledFlow(): Flow = isScreenshotCensoringEnabledFlow - .map { kaliumPreferences.getBoolean(ENABLE_SCREENSHOT_CENSORING, false) } - .onStart { emit(kaliumPreferences.getBoolean(ENABLE_SCREENSHOT_CENSORING, false)) } + .map { kaliumPreferences.getBoolean(ENABLE_SCREENSHOT_CENSORING.key, false) } + .onStart { emit(kaliumPreferences.getBoolean(ENABLE_SCREENSHOT_CENSORING.key, false)) } .distinctUntilChanged() override suspend fun persistScreenshotCensoring(enabled: Boolean) { - kaliumPreferences.putBoolean(ENABLE_SCREENSHOT_CENSORING, enabled).also { + kaliumPreferences.putBoolean(ENABLE_SCREENSHOT_CENSORING.key, enabled).also { isScreenshotCensoringEnabledFlow.tryEmit(Unit) } } - - companion object { - const val FILE_SHARING = "file_sharing" - const val GUEST_ROOM_LINK = "guest_room_link" - const val ENABLE_CLASSIFIED_DOMAINS = "enable_classified_domains" - const val ENABLE_MLS = "enable_mls" - const val E2EI_SETTINGS = "end_to_end_identity_settings" - const val E2EI_NOTIFICATION_TIME = "end_to_end_identity_notification_time" - const val ENABLE_CONFERENCE_CALLING = "enable_conference_calling" - const val USE_SFT_FOR_ONE_ON_ONE_CALLS = "use_sft_for_one_on_one_calls" - const val ENABLE_READ_RECEIPTS = "enable_read_receipts" - const val DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE = false - const val DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE = false - const val REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE = - "require_second_factor_password_challenge" - const val ENABLE_SCREENSHOT_CENSORING = "enable_screenshot_censoring" - const val ENABLE_TYPING_INDICATOR = "enable_typing_indicator" - const val APP_LOCK = "app_lock" - const val DEFAULT_PROTOCOL = "default_protocol" - } } diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt index eefeb091ae8..77a1c56e962 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserPrefsDAO.kt @@ -23,22 +23,22 @@ import com.wire.kalium.persistence.config.E2EISettingsEntity import com.wire.kalium.persistence.config.IsFileSharingEnabledEntity import com.wire.kalium.persistence.config.IsGuestRoomLinkEnabledEntity import com.wire.kalium.persistence.config.UserConfigStorage -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.APP_LOCK -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.DEFAULT_PROTOCOL -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.E2EI_NOTIFICATION_TIME -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.E2EI_SETTINGS -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_CLASSIFIED_DOMAINS -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_CONFERENCE_CALLING -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_MLS -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_READ_RECEIPTS -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_SCREENSHOT_CENSORING -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.ENABLE_TYPING_INDICATOR -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.FILE_SHARING -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.GUEST_ROOM_LINK -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE -import com.wire.kalium.persistence.config.UserConfigStorageImpl.Companion.USE_SFT_FOR_ONE_ON_ONE_CALLS +import com.wire.kalium.persistence.config.UserConfigStorage.Companion.DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE +import com.wire.kalium.persistence.config.UserConfigStorage.Companion.DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.APP_LOCK +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.DEFAULT_PROTOCOL +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.E2EI_NOTIFICATION_TIME +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.E2EI_SETTINGS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_CLASSIFIED_DOMAINS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_CONFERENCE_CALLING +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_MLS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_READ_RECEIPTS +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_SCREENSHOT_CENSORING +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.ENABLE_TYPING_INDICATOR +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.FILE_SHARING +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.GUEST_ROOM_LINK +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE +import com.wire.kalium.persistence.config.UserConfigStorage.UserPreferences.USE_SFT_FOR_ONE_ON_ONE_CALLS import com.wire.kalium.util.time.Second import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -53,27 +53,27 @@ internal class UserPrefsDAO( isStatusChanged: Boolean? ) { metadataDAO.putSerializable( - APP_LOCK, + APP_LOCK.key, AppLockConfigEntity(inactivityTimeoutSecs, isEnforced, isStatusChanged), AppLockConfigEntity.serializer(), ) } override suspend fun appLockStatus(): AppLockConfigEntity? { - return metadataDAO.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + return metadataDAO.getSerializable(APP_LOCK.key, AppLockConfigEntity.serializer()) } override fun appLockFlow(): Flow { - return metadataDAO.observeSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + return metadataDAO.observeSerializable(APP_LOCK.key, AppLockConfigEntity.serializer()) } override suspend fun setTeamAppLockAsNotified() { val newValue = - metadataDAO.getSerializable(APP_LOCK, AppLockConfigEntity.serializer()) + metadataDAO.getSerializable(APP_LOCK.key, AppLockConfigEntity.serializer()) ?.copy(isStatusChanged = false) ?: return metadataDAO.putSerializable( - APP_LOCK, + APP_LOCK.key, newValue, AppLockConfigEntity.serializer() ) @@ -81,75 +81,75 @@ internal class UserPrefsDAO( override suspend fun persistFileSharingStatus(status: Boolean, isStatusChanged: Boolean?) { metadataDAO.putSerializable( - FILE_SHARING, + FILE_SHARING.key, IsFileSharingEnabledEntity(status, isStatusChanged), IsFileSharingEnabledEntity.serializer() ) } override suspend fun isFileSharingEnabled(): IsFileSharingEnabledEntity? { - return metadataDAO.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + return metadataDAO.getSerializable(FILE_SHARING.key, IsFileSharingEnabledEntity.serializer()) } override fun isFileSharingEnabledFlow(): Flow { - return metadataDAO.observeSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + return metadataDAO.observeSerializable(FILE_SHARING.key, IsFileSharingEnabledEntity.serializer()) } override suspend fun setFileSharingAsNotified() { val newValue = - metadataDAO.getSerializable(FILE_SHARING, IsFileSharingEnabledEntity.serializer()) + metadataDAO.getSerializable(FILE_SHARING.key, IsFileSharingEnabledEntity.serializer()) ?.copy(isStatusChanged = false) ?: return metadataDAO.putSerializable( - FILE_SHARING, + FILE_SHARING.key, newValue, IsFileSharingEnabledEntity.serializer() ) } override fun isClassifiedDomainsEnabledFlow(): Flow { - return metadataDAO.observeSerializable(ENABLE_CLASSIFIED_DOMAINS, ClassifiedDomainsEntity.serializer()) + return metadataDAO.observeSerializable(ENABLE_CLASSIFIED_DOMAINS.key, ClassifiedDomainsEntity.serializer()) } override suspend fun persistClassifiedDomainsStatus(status: Boolean, classifiedDomains: List) { metadataDAO.putSerializable( - ENABLE_CLASSIFIED_DOMAINS, + ENABLE_CLASSIFIED_DOMAINS.key, ClassifiedDomainsEntity(status, classifiedDomains), ClassifiedDomainsEntity.serializer() ) } override suspend fun persistSecondFactorPasswordChallengeStatus(isRequired: Boolean) { - metadataDAO.insertValue(value = isRequired.toString(), key = REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE) + metadataDAO.insertValue(value = isRequired.toString(), key = REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE.key) } override suspend fun isSecondFactorPasswordChallengeRequired(): Boolean { - return metadataDAO.valueByKey(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE)?.toBoolean() ?: false + return metadataDAO.valueByKey(REQUIRE_SECOND_FACTOR_PASSWORD_CHALLENGE.key)?.toBoolean() ?: false } override suspend fun persistDefaultProtocol(protocol: SupportedProtocolEntity) { - metadataDAO.insertValue(value = protocol.name, key = DEFAULT_PROTOCOL) + metadataDAO.insertValue(value = protocol.name, key = DEFAULT_PROTOCOL.key) } override suspend fun defaultProtocol(): SupportedProtocolEntity { - return metadataDAO.valueByKey(DEFAULT_PROTOCOL)?.let { SupportedProtocolEntity.valueOf(it) } + return metadataDAO.valueByKey(DEFAULT_PROTOCOL.key)?.let { SupportedProtocolEntity.valueOf(it) } ?: SupportedProtocolEntity.PROTEUS } override suspend fun enableMLS(enabled: Boolean) { - metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_MLS) + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_MLS.key) } override suspend fun isMLSEnabled(): Boolean { - return metadataDAO.valueByKey(ENABLE_MLS)?.toBoolean() ?: false + return metadataDAO.valueByKey(ENABLE_MLS.key)?.toBoolean() ?: false } override suspend fun setE2EISettings(settingEntity: E2EISettingsEntity?) { if (settingEntity == null) { - metadataDAO.deleteValue(E2EI_SETTINGS) + metadataDAO.deleteValue(E2EI_SETTINGS.key) } else { metadataDAO.putSerializable( - E2EI_SETTINGS, + E2EI_SETTINGS.key, settingEntity, E2EISettingsEntity.serializer() ) @@ -157,58 +157,58 @@ internal class UserPrefsDAO( } override suspend fun getE2EISettings(): E2EISettingsEntity? { - return metadataDAO.getSerializable(E2EI_SETTINGS, E2EISettingsEntity.serializer()) + return metadataDAO.getSerializable(E2EI_SETTINGS.key, E2EISettingsEntity.serializer()) } override fun e2EISettingsFlow(): Flow { - return metadataDAO.observeSerializable(E2EI_SETTINGS, E2EISettingsEntity.serializer()) + return metadataDAO.observeSerializable(E2EI_SETTINGS.key, E2EISettingsEntity.serializer()) } override suspend fun persistConferenceCalling(enabled: Boolean) { - metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_CONFERENCE_CALLING) + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_CONFERENCE_CALLING.key) } override suspend fun isConferenceCallingEnabled(): Boolean { - return metadataDAO.valueByKey(ENABLE_CONFERENCE_CALLING)?.toBoolean() ?: DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE + return metadataDAO.valueByKey(ENABLE_CONFERENCE_CALLING.key)?.toBoolean() ?: DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE } override suspend fun isConferenceCallingEnabledFlow(): Flow { - return metadataDAO.valueByKeyFlow(ENABLE_CONFERENCE_CALLING).map { value -> + return metadataDAO.valueByKeyFlow(ENABLE_CONFERENCE_CALLING.key).map { value -> value?.toBoolean() ?: DEFAULT_CONFERENCE_CALLING_ENABLED_VALUE } } override suspend fun persistUseSftForOneOnOneCalls(shouldUse: Boolean) { - metadataDAO.insertValue(value = shouldUse.toString(), key = USE_SFT_FOR_ONE_ON_ONE_CALLS) + metadataDAO.insertValue(value = shouldUse.toString(), key = USE_SFT_FOR_ONE_ON_ONE_CALLS.key) } override suspend fun shouldUseSftForOneOnOneCalls(): Boolean { - return metadataDAO.valueByKey(USE_SFT_FOR_ONE_ON_ONE_CALLS)?.toBoolean() ?: DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE + return metadataDAO.valueByKey(USE_SFT_FOR_ONE_ON_ONE_CALLS.key)?.toBoolean() ?: DEFAULT_USE_SFT_FOR_ONE_ON_ONE_CALLS_VALUE } override suspend fun areReadReceiptsEnabled(): Flow { - return metadataDAO.valueByKeyFlow(ENABLE_READ_RECEIPTS).map { + return metadataDAO.valueByKeyFlow(ENABLE_READ_RECEIPTS.key).map { it?.toBoolean() ?: true } } override suspend fun persistReadReceipts(enabled: Boolean) { - metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_READ_RECEIPTS) + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_READ_RECEIPTS.key) } override suspend fun isTypingIndicatorEnabled(): Flow { - return metadataDAO.valueByKeyFlow(ENABLE_TYPING_INDICATOR).map { + return metadataDAO.valueByKeyFlow(ENABLE_TYPING_INDICATOR.key).map { it?.toBoolean() ?: true } } override suspend fun persistTypingIndicator(enabled: Boolean) { - metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_TYPING_INDICATOR) + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_TYPING_INDICATOR.key) } override suspend fun persistGuestRoomLinkFeatureFlag(status: Boolean, isStatusChanged: Boolean?) { metadataDAO.putSerializable( - GUEST_ROOM_LINK, + GUEST_ROOM_LINK.key, IsGuestRoomLinkEnabledEntity(status, isStatusChanged), IsGuestRoomLinkEnabledEntity.serializer() ) @@ -216,46 +216,46 @@ internal class UserPrefsDAO( override suspend fun isGuestRoomLinkEnabled(): IsGuestRoomLinkEnabledEntity? { return metadataDAO.getSerializable( - GUEST_ROOM_LINK, + GUEST_ROOM_LINK.key, IsGuestRoomLinkEnabledEntity.serializer() ) } override fun isGuestRoomLinkEnabledFlow(): Flow { return metadataDAO.observeSerializable( - GUEST_ROOM_LINK, + GUEST_ROOM_LINK.key, IsGuestRoomLinkEnabledEntity.serializer() ) } override suspend fun isScreenshotCensoringEnabledFlow(): Flow { - return metadataDAO.valueByKeyFlow(ENABLE_SCREENSHOT_CENSORING).map { + return metadataDAO.valueByKeyFlow(ENABLE_SCREENSHOT_CENSORING.key).map { it?.toBoolean() ?: false } } override suspend fun persistScreenshotCensoring(enabled: Boolean) { - metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_SCREENSHOT_CENSORING) + metadataDAO.insertValue(value = enabled.toString(), key = ENABLE_SCREENSHOT_CENSORING.key) } override suspend fun setIfAbsentE2EINotificationTime(timeStamp: Long) { getE2EINotificationTime().let { current -> if (current == null || current <= 0) - metadataDAO.insertValue(value = timeStamp.toString(), key = E2EI_NOTIFICATION_TIME) + metadataDAO.insertValue(value = timeStamp.toString(), key = E2EI_NOTIFICATION_TIME.key) } } override suspend fun getE2EINotificationTime(): Long? { - return metadataDAO.valueByKey(E2EI_NOTIFICATION_TIME)?.toLong() + return metadataDAO.valueByKey(E2EI_NOTIFICATION_TIME.key)?.toLong() } override suspend fun e2EINotificationTimeFlow(): Flow { - return metadataDAO.valueByKeyFlow(E2EI_NOTIFICATION_TIME).map { + return metadataDAO.valueByKeyFlow(E2EI_NOTIFICATION_TIME.key).map { it?.toLong() } } override suspend fun updateE2EINotificationTime(timeStamp: Long) { - metadataDAO.insertValue(value = timeStamp.toString(), key = E2EI_NOTIFICATION_TIME) + metadataDAO.insertValue(value = timeStamp.toString(), key = E2EI_NOTIFICATION_TIME.key) } } diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt index d94cfeaad41..b2a73455f7a 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt @@ -21,6 +21,11 @@ package com.wire.kalium.persistence.kmmSettings import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorage import com.wire.kalium.persistence.config.UserConfigStorage +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) expect class UserPrefBuilder { val lastRetrievedNotificationEventStorage: LastRetrievedNotificationEventStorage val userConfigStorage: UserConfigStorage diff --git a/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt index 6666485d928..adf1fbbe141 100644 --- a/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ b/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt @@ -21,6 +21,11 @@ package com.wire.kalium.persistence.kmmSettings import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorage import com.wire.kalium.persistence.config.UserConfigStorage +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) actual class UserPrefBuilder { actual val lastRetrievedNotificationEventStorage: LastRetrievedNotificationEventStorage get() = TODO("Not yet implemented") diff --git a/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt index a891fcab7c9..b02f5c3e7fa 100644 --- a/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ b/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt @@ -24,6 +24,11 @@ import com.wire.kalium.persistence.config.UserConfigStorage import com.wire.kalium.persistence.config.UserConfigStorageImpl import com.wire.kalium.persistence.dao.UserIDEntity +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) actual class UserPrefBuilder( userId: UserIDEntity, rootPath: String, diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index a19b1e1ba50..d79c8a05a5c 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -1299,7 +1299,12 @@ public class UserSessionScope internal constructor( get() = SlowSyncRecoveryHandlerImpl(logout) private val syncMigrationStepsProvider: () -> SyncMigrationStepsProvider = { - SyncMigrationStepsProviderImpl(lazy { accountRepository }, selfTeamId) + SyncMigrationStepsProviderImpl( + accountRepository = lazy { accountRepository }, + selfTeamIdProvider = selfTeamId, + oldUserConfigStorage = userStorage.preferences.userConfigStorage, + newUserConfigStorage = userStorage.database.userPrefsDAO + ) } private val slowSyncManager: SlowSyncManager by lazy { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt index e1b85ae4a6a..76b9096c572 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt @@ -66,7 +66,7 @@ internal interface SlowSyncManager { * Useful when a new step is added to Slow Sync, or when we fix some bug in Slow Sync, * and we'd like to get all users to take advantage of the fix. */ - const val CURRENT_VERSION = 10 + const val CURRENT_VERSION = 11 // because we already had version 9, the next version should be 10 val MIN_RETRY_DELAY = 1.seconds diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt index e136ce37280..54474c02bcd 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt @@ -20,7 +20,9 @@ package com.wire.kalium.logic.sync.slow.migration import com.wire.kalium.logic.data.id.SelfTeamIdProvider import com.wire.kalium.logic.data.user.AccountRepository import com.wire.kalium.logic.sync.slow.migration.steps.SyncMigrationStep +import com.wire.kalium.logic.sync.slow.migration.steps.SyncMigrationStep_10_11 import com.wire.kalium.logic.sync.slow.migration.steps.SyncMigrationStep_6_7 +import com.wire.kalium.persistence.config.UserConfigStorage import io.mockative.Mockable @Mockable @@ -31,11 +33,14 @@ internal interface SyncMigrationStepsProvider { @Suppress("MagicNumber") internal class SyncMigrationStepsProviderImpl( accountRepository: Lazy, - selfTeamIdProvider: SelfTeamIdProvider + selfTeamIdProvider: SelfTeamIdProvider, + oldUserConfigStorage: UserConfigStorage, + newUserConfigStorage: UserConfigStorage ) : SyncMigrationStepsProvider { private val steps = mapOf( - 7 to lazy { SyncMigrationStep_6_7(accountRepository, selfTeamIdProvider) } + 7 to lazy { SyncMigrationStep_6_7(accountRepository, selfTeamIdProvider) }, + 11 to lazy { SyncMigrationStep_10_11(oldUserConfigStorage, newUserConfigStorage) } ) override fun getMigrationSteps(fromVersion: Int, toVersion: Int): List { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt new file mode 100644 index 00000000000..aead775c8aa --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt @@ -0,0 +1,70 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.sync.slow.migration.steps + +import com.wire.kalium.common.error.CoreFailure +import com.wire.kalium.common.functional.Either +import com.wire.kalium.common.functional.right +import com.wire.kalium.common.logger.kaliumLogger +import com.wire.kalium.persistence.config.UserConfigStorage +import kotlinx.coroutines.flow.first + +@Suppress("ClassNaming", "MagicNumber") +internal class SyncMigrationStep_10_11( + private val oldUserConfigStorage: UserConfigStorage, + private val newUserConfigStorage: UserConfigStorage +) : SyncMigrationStep { + + override val version: Int = 11 + + @Suppress("TooGenericExceptionCaught") + override suspend fun invoke(): Either { + return try { + migrateLocallyManagedPreferences() + Unit.right() + } catch (e: Exception) { + // Log but don't fail - preferences will be set by user in case of failure. + kaliumLogger.w("Migration 10->11 failed, continuing: ${e.message}") + Unit.right() + } + } + + private suspend fun migrateLocallyManagedPreferences() { + oldUserConfigStorage.areReadReceiptsEnabled().first().let { isEnabled -> + newUserConfigStorage.persistReadReceipts(isEnabled) + kaliumLogger.d("Migrated read receipts: $isEnabled") + } + + oldUserConfigStorage.isTypingIndicatorEnabled().first().let { isEnabled -> + newUserConfigStorage.persistTypingIndicator(isEnabled) + kaliumLogger.d("Migrated typing indicator: $isEnabled") + } + + oldUserConfigStorage.isScreenshotCensoringEnabledFlow().first().let { isEnabled -> + newUserConfigStorage.persistScreenshotCensoring(isEnabled) + kaliumLogger.d("Migrated screenshot censoring: $isEnabled") + } + + oldUserConfigStorage.getE2EINotificationTime()?.let { timestamp -> + if (timestamp > 0) { + newUserConfigStorage.updateE2EINotificationTime(timestamp) + kaliumLogger.d("Migrated E2EI notification time: $timestamp") + } + } + } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt index 2652c3010e8..ba12e9121cd 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt @@ -17,11 +17,14 @@ */ package com.wire.kalium.logic.sync.slow.migration +import com.wire.kalium.logic.sync.slow.migration.steps.SyncMigrationStep_10_11 import com.wire.kalium.logic.sync.slow.migration.steps.SyncMigrationStep_6_7 import com.wire.kalium.logic.util.arrangement.provider.SelfTeamIdProviderArrangement import com.wire.kalium.logic.util.arrangement.provider.SelfTeamIdProviderArrangementImpl import com.wire.kalium.logic.util.arrangement.repository.AccountRepositoryArrangement import com.wire.kalium.logic.util.arrangement.repository.AccountRepositoryArrangementImpl +import com.wire.kalium.persistence.config.FakeUserConfigStorage +import com.wire.kalium.persistence.config.inMemoryUserConfigStorage import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs @@ -34,8 +37,13 @@ class SyncMigrationStepsProviderTest { val (_, provider) = Arrangement().arrange() provider.getMigrationSteps(Int.MIN_VALUE, Int.MAX_VALUE).also { - assertIs(it.first()) - assertEquals(7, it.first().version) + val firstManualMigration = it.first() + val lastManualMigration = it.last() + assertIs(firstManualMigration) + assertEquals(7, firstManualMigration.version) + + assertIs(lastManualMigration) + assertEquals(11, lastManualMigration.version) } } @@ -53,8 +61,10 @@ class SyncMigrationStepsProviderTest { SelfTeamIdProviderArrangement by SelfTeamIdProviderArrangementImpl() { private val provider: SyncMigrationStepsProvider = SyncMigrationStepsProviderImpl( - lazy { accountRepository }, - selfTeamIdProvider + accountRepository = lazy { accountRepository }, + selfTeamIdProvider = selfTeamIdProvider, + oldUserConfigStorage = inMemoryUserConfigStorage(), + newUserConfigStorage = FakeUserConfigStorage() ) fun arrange(block: Arrangement.() -> Unit = { }) = apply(block).let { this to provider } From bc85670add54abc0e80f61df9000609dfff65a3d Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Wed, 4 Feb 2026 10:05:08 +0100 Subject: [PATCH 3/4] refactor: create user pref only during migration (WPB-23210) (#3835) * refactor: implement userprefs dao as replacements of user configs impl. * add test * add test * refactor: change to enums for a way to wrap all the configs * refactor: execute migration of local props and increase slow sync to have updated * fix detekt * refactor: remove UserPrefBuilder and create UserConfigStorage only during migration --------- Co-authored-by: yamilmedina --- .../config/UserConfigStorageFactory.kt | 52 +++++++++++++++++++ .../kmmSettings/UserPrefBuilder.kt | 1 + .../config/UserConfigStorageFactory.kt | 51 ++++++++++++++++++ .../config/UserConfigStorageFactory.kt | 39 ++++++++++++++ .../config/UserConfigStorageFactory.kt | 36 +++++++++++++ .../config/UserConfigStorageFactory.kt | 51 ++++++++++++++++++ .../logic/di/PlatformUserStorageProvider.kt | 4 +- .../logic/di/UserConfigStorageFactory.kt | 38 ++++++++++++++ .../logic/di/PlatformUserStorageProvider.kt | 4 +- .../logic/di/UserConfigStorageFactory.kt | 38 ++++++++++++++ .../logic/di/UserConfigStorageFactory.kt | 35 +++++++++++++ .../kalium/logic/di/UserStorageProvider.kt | 3 +- .../kalium/logic/feature/UserSessionScope.kt | 9 ++-- .../feature/auth/ClearUserDataUseCase.kt | 2 - .../migration/SyncMigrationStepsProvider.kt | 4 +- .../steps/SyncMigrationStep_10_11.kt | 20 +++---- .../SyncMigrationStepsProviderTest.kt | 4 +- .../di/PlatformUserStorageProperties.kt | 20 +++++++ .../di/UserConfigStorageFactory.kt | 32 ++++++++++++ .../logic/di/PlatformUserStorageProvider.kt | 4 +- .../logic/di/UserConfigStorageFactory.kt | 38 ++++++++++++++ 21 files changed, 455 insertions(+), 30 deletions(-) create mode 100644 data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt create mode 100644 data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt create mode 100644 data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt create mode 100644 data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt create mode 100644 data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt create mode 100644 logic/src/androidMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt create mode 100644 logic/src/appleMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt create mode 100644 logic/src/jsMain/kotlin/com.wire.kalium.logic/di/PlatformUserStorageProperties.kt create mode 100644 logic/src/jsMain/kotlin/com.wire.kalium.logic/di/UserConfigStorageFactory.kt create mode 100644 logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt diff --git a/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt b/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..ecb3bbbea4f --- /dev/null +++ b/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt @@ -0,0 +1,52 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.persistence.config + +import android.content.Context +import com.wire.kalium.persistence.dao.UserIDEntity +import com.wire.kalium.persistence.kmmSettings.EncryptedSettingsPlatformParam +import com.wire.kalium.persistence.kmmSettings.KaliumPreferencesSettings +import com.wire.kalium.persistence.kmmSettings.SettingOptions +import com.wire.kalium.persistence.kmmSettings.buildSettings + +@Suppress("DEPRECATION") +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) +actual class UserConfigStorageFactory actual constructor() { + /** + * Creates a [UserConfigStorage] instance for Android. + * @param userId The user ID entity + * @param shouldEncryptData Whether to encrypt the data + * @param platformParam Must be an Android [Context] + */ + actual fun create( + userId: UserIDEntity, + shouldEncryptData: Boolean, + platformParam: Any + ): UserConfigStorage { + require(platformParam is Context) { "platformParam must be an Android Context" } + val settings = buildSettings( + SettingOptions.UserSettings(shouldEncryptData, userId), + EncryptedSettingsPlatformParam(platformParam) + ) + return UserConfigStorageImpl(KaliumPreferencesSettings(settings)) + } +} diff --git a/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt index bf803f1c05e..268b48cd542 100644 --- a/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ b/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt @@ -29,6 +29,7 @@ import com.wire.kalium.persistence.dao.UserIDEntity "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + "Just kept for migration purposes.", ReplaceWith("No replacement available"), + level = DeprecationLevel.ERROR ) actual class UserPrefBuilder( userId: UserIDEntity, diff --git a/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt b/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..0f28f35101b --- /dev/null +++ b/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt @@ -0,0 +1,51 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.persistence.config + +import com.wire.kalium.persistence.dao.UserIDEntity +import com.wire.kalium.persistence.kmmSettings.EncryptedSettingsPlatformParam +import com.wire.kalium.persistence.kmmSettings.KaliumPreferencesSettings +import com.wire.kalium.persistence.kmmSettings.SettingOptions +import com.wire.kalium.persistence.kmmSettings.buildSettings + +@Suppress("DEPRECATION") +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) +actual class UserConfigStorageFactory actual constructor() { + /** + * Creates a [UserConfigStorage] instance for Apple platforms. + * @param userId The user ID entity + * @param shouldEncryptData Whether to encrypt the data (ignored on Apple, uses Keychain) + * @param platformParam Must be a [String] representing the service name for Keychain + */ + actual fun create( + userId: UserIDEntity, + shouldEncryptData: Boolean, + platformParam: Any + ): UserConfigStorage { + require(platformParam is String) { "platformParam must be a String (service name)" } + val settings = buildSettings( + SettingOptions.UserSettings(shouldEncryptData, userId), + EncryptedSettingsPlatformParam(platformParam) + ) + return UserConfigStorageImpl(KaliumPreferencesSettings(settings)) + } +} diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..ffc37a1bd03 --- /dev/null +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt @@ -0,0 +1,39 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.persistence.config + +import com.wire.kalium.persistence.dao.UserIDEntity + +/** + * Factory for creating [UserConfigStorage] instances. + * This is used during migration from SharedPreferences to database storage. + * Creating the storage only when needed avoids creating SharedPreferences + * when migration is not required. + */ +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) +expect class UserConfigStorageFactory() { + fun create( + userId: UserIDEntity, + shouldEncryptData: Boolean, + platformParam: Any + ): UserConfigStorage +} diff --git a/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt b/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..f9aea6dd994 --- /dev/null +++ b/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt @@ -0,0 +1,36 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.persistence.config + +import com.wire.kalium.persistence.dao.UserIDEntity + +@Suppress("DEPRECATION") +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) +actual class UserConfigStorageFactory actual constructor() { + actual fun create( + userId: UserIDEntity, + shouldEncryptData: Boolean, + platformParam: Any + ): UserConfigStorage { + TODO("JS implementation not yet available") + } +} diff --git a/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt b/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..c3ffbf0421e --- /dev/null +++ b/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorageFactory.kt @@ -0,0 +1,51 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.persistence.config + +import com.wire.kalium.persistence.dao.UserIDEntity +import com.wire.kalium.persistence.kmmSettings.EncryptedSettingsPlatformParam +import com.wire.kalium.persistence.kmmSettings.KaliumPreferencesSettings +import com.wire.kalium.persistence.kmmSettings.SettingOptions +import com.wire.kalium.persistence.kmmSettings.buildSettings + +@Suppress("DEPRECATION") +@Deprecated( + "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + + "Just kept for migration purposes.", + ReplaceWith("No replacement available"), +) +actual class UserConfigStorageFactory actual constructor() { + /** + * Creates a [UserConfigStorage] instance for JVM. + * @param userId The user ID entity + * @param shouldEncryptData Whether to encrypt the data + * @param platformParam Must be a [String] representing the root path + */ + actual fun create( + userId: UserIDEntity, + shouldEncryptData: Boolean, + platformParam: Any + ): UserConfigStorage { + require(platformParam is String) { "platformParam must be a String (root path)" } + val settings = buildSettings( + SettingOptions.UserSettings(shouldEncryptData, userId), + EncryptedSettingsPlatformParam(platformParam) + ) + return UserConfigStorageImpl(KaliumPreferencesSettings(settings)) + } +} diff --git a/logic/src/androidMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt b/logic/src/androidMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt index a225461422c..2806b963c90 100644 --- a/logic/src/androidMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt +++ b/logic/src/androidMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt @@ -22,7 +22,6 @@ import com.wire.kalium.logic.data.id.toDao import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.persistence.db.PlatformDatabaseData import com.wire.kalium.persistence.db.userDatabaseBuilder -import com.wire.kalium.persistence.kmmSettings.UserPrefBuilder import com.wire.kalium.util.KaliumDispatcherImpl internal actual class PlatformUserStorageProvider : UserStorageProvider() { @@ -33,7 +32,6 @@ internal actual class PlatformUserStorageProvider : UserStorageProvider() { dbInvalidationControlEnabled: Boolean ): UserStorage { val userIdEntity = userId.toDao() - val pref = UserPrefBuilder(userIdEntity, platformProperties.applicationContext, shouldEncryptData) val databasePassphrase = if (shouldEncryptData) { platformProperties.securityHelper.userDBSecret(userId) @@ -48,6 +46,6 @@ internal actual class PlatformUserStorageProvider : UserStorageProvider() { enableWAL = true, dbInvalidationControlEnabled = dbInvalidationControlEnabled ) - return UserStorage(database, pref) + return UserStorage(database) } } diff --git a/logic/src/androidMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt b/logic/src/androidMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..98e89894d4a --- /dev/null +++ b/logic/src/androidMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt @@ -0,0 +1,38 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.di + +import com.wire.kalium.logic.data.id.toDao +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.persistence.config.UserConfigStorage +import com.wire.kalium.persistence.config.UserConfigStorageFactory as PersistenceUserConfigStorageFactory + +@Suppress("DEPRECATION") +internal actual class UserConfigStorageFactory actual constructor() { + private val persistenceFactory = PersistenceUserConfigStorageFactory() + + actual fun create( + userId: UserId, + shouldEncryptData: Boolean, + platformProperties: PlatformUserStorageProperties + ): UserConfigStorage = persistenceFactory.create( + userId = userId.toDao(), + shouldEncryptData = shouldEncryptData, + platformParam = platformProperties.applicationContext + ) +} diff --git a/logic/src/appleMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt b/logic/src/appleMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt index 92ccebe529c..de5bdaa6108 100644 --- a/logic/src/appleMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt +++ b/logic/src/appleMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt @@ -23,7 +23,6 @@ import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.persistence.db.PlatformDatabaseData import com.wire.kalium.persistence.db.StorageData import com.wire.kalium.persistence.db.userDatabaseBuilder -import com.wire.kalium.persistence.kmmSettings.UserPrefBuilder import com.wire.kalium.util.KaliumDispatcherImpl internal actual class PlatformUserStorageProvider actual constructor() : UserStorageProvider() { @@ -34,7 +33,6 @@ internal actual class PlatformUserStorageProvider actual constructor() : UserSto dbInvalidationControlEnabled: Boolean ): UserStorage { val userIdEntity = userId.toDao() - val pref = UserPrefBuilder(userIdEntity, platformProperties.rootPath, shouldEncryptData) val database = userDatabaseBuilder( platformDatabaseData = PlatformDatabaseData(StorageData.FileBacked(platformProperties.rootStoragePath)), userId = userIdEntity, @@ -43,6 +41,6 @@ internal actual class PlatformUserStorageProvider actual constructor() : UserSto enableWAL = true, dbInvalidationControlEnabled = dbInvalidationControlEnabled ) - return UserStorage(database, pref) + return UserStorage(database) } } diff --git a/logic/src/appleMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt b/logic/src/appleMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..b63bdbfaa7b --- /dev/null +++ b/logic/src/appleMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt @@ -0,0 +1,38 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.di + +import com.wire.kalium.logic.data.id.toDao +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.persistence.config.UserConfigStorage +import com.wire.kalium.persistence.config.UserConfigStorageFactory as PersistenceUserConfigStorageFactory + +@Suppress("DEPRECATION") +internal actual class UserConfigStorageFactory actual constructor() { + private val persistenceFactory = PersistenceUserConfigStorageFactory() + + actual fun create( + userId: UserId, + shouldEncryptData: Boolean, + platformProperties: PlatformUserStorageProperties + ): UserConfigStorage = persistenceFactory.create( + userId = userId.toDao(), + shouldEncryptData = shouldEncryptData, + platformParam = platformProperties.rootPath + ) +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..e79086d03b7 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt @@ -0,0 +1,35 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.di + +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.persistence.config.UserConfigStorage + +/** + * Factory for creating [UserConfigStorage] lazily. + * This is used during migration from SharedPreferences to database storage. + * Creating the storage only when needed avoids creating SharedPreferences + * when migration is not required. + */ +internal expect class UserConfigStorageFactory() { + fun create( + userId: UserId, + shouldEncryptData: Boolean, + platformProperties: PlatformUserStorageProperties + ): UserConfigStorage +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserStorageProvider.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserStorageProvider.kt index 35aac86edb5..cfa02b41c58 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserStorageProvider.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/di/UserStorageProvider.kt @@ -21,9 +21,8 @@ package com.wire.kalium.logic.di import co.touchlab.stately.collections.ConcurrentMutableMap import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.persistence.db.UserDatabaseBuilder -import com.wire.kalium.persistence.kmmSettings.UserPrefBuilder -internal data class UserStorage(val database: UserDatabaseBuilder, val preferences: UserPrefBuilder) +internal data class UserStorage(val database: UserDatabaseBuilder) internal abstract class UserStorageProvider { private val inMemoryUserStorage: ConcurrentMutableMap = ConcurrentMutableMap() internal fun getOrCreate( diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index d79c8a05a5c..a5c95a5f07d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -194,6 +194,7 @@ import com.wire.kalium.logic.data.user.UserRepository import com.wire.kalium.logic.di.MapperProvider import com.wire.kalium.logic.di.PlatformUserStorageProperties import com.wire.kalium.logic.di.RootPathsProvider +import com.wire.kalium.logic.di.UserConfigStorageFactory import com.wire.kalium.logic.di.UserStorageProvider import com.wire.kalium.logic.feature.analytics.AnalyticsIdentifierManager import com.wire.kalium.logic.feature.analytics.GetAnalyticsContactsDataUseCase @@ -558,7 +559,7 @@ public class UserSessionScope internal constructor( private val userSessionScopeProvider: UserSessionScopeProvider, userStorageProvider: UserStorageProvider, private val clientConfig: ClientConfig, - platformUserStorageProperties: PlatformUserStorageProperties, + private val platformUserStorageProperties: PlatformUserStorageProperties, networkStateObserver: NetworkStateObserver, private val logoutCallback: LogoutCallback, ) : CoroutineScope { @@ -1302,8 +1303,10 @@ public class UserSessionScope internal constructor( SyncMigrationStepsProviderImpl( accountRepository = lazy { accountRepository }, selfTeamIdProvider = selfTeamId, - oldUserConfigStorage = userStorage.preferences.userConfigStorage, - newUserConfigStorage = userStorage.database.userPrefsDAO + oldUserConfigStorage = lazy { + UserConfigStorageFactory().create(userId, kaliumConfigs.shouldEncryptData, platformUserStorageProperties) + }, + newUserConfigStorage = lazy { userStorage.database.userPrefsDAO } ) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/ClearUserDataUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/ClearUserDataUseCase.kt index 58f6d507d39..3334f940281 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/ClearUserDataUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/ClearUserDataUseCase.kt @@ -39,7 +39,5 @@ internal class ClearUserDataUseCaseImpl internal constructor( private fun clearUserStorage() { userStorage.database.nuke() - // exclude clientId clear from this step - userStorage.preferences.clear() } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt index 54474c02bcd..b90e2f5092c 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProvider.kt @@ -34,8 +34,8 @@ internal interface SyncMigrationStepsProvider { internal class SyncMigrationStepsProviderImpl( accountRepository: Lazy, selfTeamIdProvider: SelfTeamIdProvider, - oldUserConfigStorage: UserConfigStorage, - newUserConfigStorage: UserConfigStorage + oldUserConfigStorage: Lazy, + newUserConfigStorage: Lazy ) : SyncMigrationStepsProvider { private val steps = mapOf( diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt index aead775c8aa..cffd2424b6d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/migration/steps/SyncMigrationStep_10_11.kt @@ -26,8 +26,8 @@ import kotlinx.coroutines.flow.first @Suppress("ClassNaming", "MagicNumber") internal class SyncMigrationStep_10_11( - private val oldUserConfigStorage: UserConfigStorage, - private val newUserConfigStorage: UserConfigStorage + private val oldUserConfigStorage: Lazy, + private val newUserConfigStorage: Lazy ) : SyncMigrationStep { override val version: Int = 11 @@ -45,24 +45,24 @@ internal class SyncMigrationStep_10_11( } private suspend fun migrateLocallyManagedPreferences() { - oldUserConfigStorage.areReadReceiptsEnabled().first().let { isEnabled -> - newUserConfigStorage.persistReadReceipts(isEnabled) + oldUserConfigStorage.value.areReadReceiptsEnabled().first().let { isEnabled -> + newUserConfigStorage.value.persistReadReceipts(isEnabled) kaliumLogger.d("Migrated read receipts: $isEnabled") } - oldUserConfigStorage.isTypingIndicatorEnabled().first().let { isEnabled -> - newUserConfigStorage.persistTypingIndicator(isEnabled) + oldUserConfigStorage.value.isTypingIndicatorEnabled().first().let { isEnabled -> + newUserConfigStorage.value.persistTypingIndicator(isEnabled) kaliumLogger.d("Migrated typing indicator: $isEnabled") } - oldUserConfigStorage.isScreenshotCensoringEnabledFlow().first().let { isEnabled -> - newUserConfigStorage.persistScreenshotCensoring(isEnabled) + oldUserConfigStorage.value.isScreenshotCensoringEnabledFlow().first().let { isEnabled -> + newUserConfigStorage.value.persistScreenshotCensoring(isEnabled) kaliumLogger.d("Migrated screenshot censoring: $isEnabled") } - oldUserConfigStorage.getE2EINotificationTime()?.let { timestamp -> + oldUserConfigStorage.value.getE2EINotificationTime()?.let { timestamp -> if (timestamp > 0) { - newUserConfigStorage.updateE2EINotificationTime(timestamp) + newUserConfigStorage.value.updateE2EINotificationTime(timestamp) kaliumLogger.d("Migrated E2EI notification time: $timestamp") } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt index ba12e9121cd..df77c76259e 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/migration/SyncMigrationStepsProviderTest.kt @@ -63,8 +63,8 @@ class SyncMigrationStepsProviderTest { private val provider: SyncMigrationStepsProvider = SyncMigrationStepsProviderImpl( accountRepository = lazy { accountRepository }, selfTeamIdProvider = selfTeamIdProvider, - oldUserConfigStorage = inMemoryUserConfigStorage(), - newUserConfigStorage = FakeUserConfigStorage() + oldUserConfigStorage = lazy { inMemoryUserConfigStorage() }, + newUserConfigStorage = lazy { FakeUserConfigStorage() } ) fun arrange(block: Arrangement.() -> Unit = { }) = apply(block).let { this to provider } diff --git a/logic/src/jsMain/kotlin/com.wire.kalium.logic/di/PlatformUserStorageProperties.kt b/logic/src/jsMain/kotlin/com.wire.kalium.logic/di/PlatformUserStorageProperties.kt new file mode 100644 index 00000000000..49821efe556 --- /dev/null +++ b/logic/src/jsMain/kotlin/com.wire.kalium.logic/di/PlatformUserStorageProperties.kt @@ -0,0 +1,20 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.di + +internal actual class PlatformUserStorageProperties diff --git a/logic/src/jsMain/kotlin/com.wire.kalium.logic/di/UserConfigStorageFactory.kt b/logic/src/jsMain/kotlin/com.wire.kalium.logic/di/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..097a3cf7df7 --- /dev/null +++ b/logic/src/jsMain/kotlin/com.wire.kalium.logic/di/UserConfigStorageFactory.kt @@ -0,0 +1,32 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.di + +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.persistence.config.UserConfigStorage + +@Suppress("DEPRECATION") +internal actual class UserConfigStorageFactory actual constructor() { + actual fun create( + userId: UserId, + shouldEncryptData: Boolean, + platformProperties: PlatformUserStorageProperties + ): UserConfigStorage { + TODO("JS implementation not yet available") + } +} diff --git a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt index 44e00dfc68b..1c9073e0ffa 100644 --- a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt +++ b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/PlatformUserStorageProvider.kt @@ -24,7 +24,6 @@ import com.wire.kalium.persistence.db.PlatformDatabaseData import com.wire.kalium.persistence.db.StorageData import com.wire.kalium.persistence.db.inMemoryDatabase import com.wire.kalium.persistence.db.userDatabaseBuilder -import com.wire.kalium.persistence.kmmSettings.UserPrefBuilder import com.wire.kalium.util.KaliumDispatcherImpl internal actual class PlatformUserStorageProvider : UserStorageProvider() { @@ -35,7 +34,6 @@ internal actual class PlatformUserStorageProvider : UserStorageProvider() { dbInvalidationControlEnabled: Boolean ): UserStorage { val userIdEntity = userId.toDao() - val pref = UserPrefBuilder(userIdEntity, platformProperties.rootPath, shouldEncryptData) val databaseInfo = platformProperties.databaseInfo val database = when (databaseInfo) { @@ -55,6 +53,6 @@ internal actual class PlatformUserStorageProvider : UserStorageProvider() { inMemoryDatabase(userIdEntity, KaliumDispatcherImpl.io) } } - return UserStorage(database, pref) + return UserStorage(database) } } diff --git a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt new file mode 100644 index 00000000000..b63bdbfaa7b --- /dev/null +++ b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/di/UserConfigStorageFactory.kt @@ -0,0 +1,38 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.di + +import com.wire.kalium.logic.data.id.toDao +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.persistence.config.UserConfigStorage +import com.wire.kalium.persistence.config.UserConfigStorageFactory as PersistenceUserConfigStorageFactory + +@Suppress("DEPRECATION") +internal actual class UserConfigStorageFactory actual constructor() { + private val persistenceFactory = PersistenceUserConfigStorageFactory() + + actual fun create( + userId: UserId, + shouldEncryptData: Boolean, + platformProperties: PlatformUserStorageProperties + ): UserConfigStorage = persistenceFactory.create( + userId = userId.toDao(), + shouldEncryptData = shouldEncryptData, + platformParam = platformProperties.rootPath + ) +} From cc3a15cc6a129288bffc47fb71412649bc2ff974 Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Wed, 4 Feb 2026 11:25:29 +0100 Subject: [PATCH 4/4] feat: remove UserPrefBuilder.kt --- .../kmmSettings/UserPrefBuilder.kt | 55 ------------------- .../kmmSettings/UserPrefBuilder.kt | 53 ------------------ .../LastRetrievedNotificationEventStorage.kt | 52 ------------------ .../persistence/config/UserConfigStorage.kt | 1 + .../kmmSettings/UserPrefBuilder.kt | 33 ----------- .../kmmSettings/UserPrefBuilder.kt | 39 ------------- .../kmmSettings/UserPrefBuilder.kt | 54 ------------------ 7 files changed, 1 insertion(+), 286 deletions(-) delete mode 100644 data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt delete mode 100644 data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt delete mode 100644 data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/client/LastRetrievedNotificationEventStorage.kt delete mode 100644 data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt delete mode 100644 data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt delete mode 100644 data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt diff --git a/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt deleted file mode 100644 index 268b48cd542..00000000000 --- a/data/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -package com.wire.kalium.persistence.kmmSettings - -import android.content.Context -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorage -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorageImpl -import com.wire.kalium.persistence.config.UserConfigStorage -import com.wire.kalium.persistence.config.UserConfigStorageImpl -import com.wire.kalium.persistence.dao.UserIDEntity - -@Deprecated( - "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + - "Just kept for migration purposes.", - ReplaceWith("No replacement available"), - level = DeprecationLevel.ERROR -) -actual class UserPrefBuilder( - userId: UserIDEntity, - context: Context, - shouldEncryptData: Boolean = true -) { - private val encryptedSettingsHolder = - KaliumPreferencesSettings( - buildSettings( - SettingOptions.UserSettings(shouldEncryptData = shouldEncryptData, userIDEntity = userId), - EncryptedSettingsPlatformParam(context) - ) - ) - - actual val lastRetrievedNotificationEventStorage: LastRetrievedNotificationEventStorage - get() = LastRetrievedNotificationEventStorageImpl(encryptedSettingsHolder) - - actual val userConfigStorage: UserConfigStorage = UserConfigStorageImpl(encryptedSettingsHolder) - - actual fun clear() { - encryptedSettingsHolder.nuke() - } -} diff --git a/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt deleted file mode 100644 index 46a4f8d9ad9..00000000000 --- a/data/persistence/src/appleMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -package com.wire.kalium.persistence.kmmSettings - -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorage -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorageImpl -import com.wire.kalium.persistence.config.UserConfigStorage -import com.wire.kalium.persistence.config.UserConfigStorageImpl -import com.wire.kalium.persistence.dao.UserIDEntity - -@Deprecated( - "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + - "Just kept for migration purposes.", - ReplaceWith("No replacement available"), -) -actual class UserPrefBuilder constructor( - userId: UserIDEntity, - rootPath: String, - shouldEncryptData: Boolean = true -) { - - private val kaliumPreferences = - KaliumPreferencesSettings( - buildSettings(SettingOptions.UserSettings(shouldEncryptData, userId), EncryptedSettingsPlatformParam(rootPath)) - ) - - actual val lastRetrievedNotificationEventStorage: LastRetrievedNotificationEventStorage - get() = LastRetrievedNotificationEventStorageImpl(kaliumPreferences) - - actual fun clear() { - kaliumPreferences.nuke() - } - - actual val userConfigStorage: UserConfigStorage = - UserConfigStorageImpl(kaliumPreferences) - -} diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/client/LastRetrievedNotificationEventStorage.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/client/LastRetrievedNotificationEventStorage.kt deleted file mode 100644 index da2586ee5f5..00000000000 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/client/LastRetrievedNotificationEventStorage.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -package com.wire.kalium.persistence.client - -import com.wire.kalium.persistence.kmmSettings.KaliumPreferences - -interface LastRetrievedNotificationEventStorage { - /** - * to save the id of the last event retrieved from the notifications stream - */ - fun saveEvent(eventId: String) - - /** - * get the id of the last saved event if one exists - */ - fun getLastEventId(): String? -} - -internal class LastRetrievedNotificationEventStorageImpl internal constructor( - private val kaliumPreferences: KaliumPreferences -) : LastRetrievedNotificationEventStorage { - - override fun saveEvent(eventId: String) { - kaliumPreferences.putString( - LAST_NOTIFICATION_STREAM_EVENT_ID, - eventId - ) - } - - override fun getLastEventId(): String? = - kaliumPreferences.getString(LAST_NOTIFICATION_STREAM_EVENT_ID) - - private companion object { - const val LAST_NOTIFICATION_STREAM_EVENT_ID = "last_notification_stream_event_id" - } -} diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt index 808e39c9f61..be651841497 100644 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt +++ b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/config/UserConfigStorage.kt @@ -48,6 +48,7 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlin.time.Duration +@Deprecated("Use UserPrefsDAO instead. This will be removed in future versions.", ReplaceWith("UserPrefsDAO")) @Suppress("TooManyFunctions") interface UserConfigStorage { diff --git a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt deleted file mode 100644 index b2a73455f7a..00000000000 --- a/data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -package com.wire.kalium.persistence.kmmSettings - -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorage -import com.wire.kalium.persistence.config.UserConfigStorage - -@Deprecated( - "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + - "Just kept for migration purposes.", - ReplaceWith("No replacement available"), -) -expect class UserPrefBuilder { - val lastRetrievedNotificationEventStorage: LastRetrievedNotificationEventStorage - val userConfigStorage: UserConfigStorage - fun clear() -} diff --git a/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt deleted file mode 100644 index adf1fbbe141..00000000000 --- a/data/persistence/src/jsMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -package com.wire.kalium.persistence.kmmSettings - -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorage -import com.wire.kalium.persistence.config.UserConfigStorage - -@Deprecated( - "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + - "Just kept for migration purposes.", - ReplaceWith("No replacement available"), -) -actual class UserPrefBuilder { - actual val lastRetrievedNotificationEventStorage: LastRetrievedNotificationEventStorage - get() = TODO("Not yet implemented") - - actual fun clear() { - TODO("Not yet implemented") - } - - actual val userConfigStorage: UserConfigStorage - get() = TODO("Not yet implemented") -} diff --git a/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt b/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt deleted file mode 100644 index b02f5c3e7fa..00000000000 --- a/data/persistence/src/jvmMain/kotlin/com/wire/kalium/persistence/kmmSettings/UserPrefBuilder.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -package com.wire.kalium.persistence.kmmSettings - -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorage -import com.wire.kalium.persistence.client.LastRetrievedNotificationEventStorageImpl -import com.wire.kalium.persistence.config.UserConfigStorage -import com.wire.kalium.persistence.config.UserConfigStorageImpl -import com.wire.kalium.persistence.dao.UserIDEntity - -@Deprecated( - "Scheduled for removal in future versions, User KMM Settings are now replaced by database implementation." + - "Just kept for migration purposes.", - ReplaceWith("No replacement available"), -) -actual class UserPrefBuilder( - userId: UserIDEntity, - rootPath: String, - shouldEncryptData: Boolean = true -) { - - private val kaliumPref = - KaliumPreferencesSettings( - buildSettings( - SettingOptions.UserSettings(shouldEncryptData, userId), - EncryptedSettingsPlatformParam(rootPath) - ) - ) - - actual val lastRetrievedNotificationEventStorage: LastRetrievedNotificationEventStorage - get() = LastRetrievedNotificationEventStorageImpl(kaliumPref) - actual val userConfigStorage: UserConfigStorage = UserConfigStorageImpl(kaliumPref) - - actual fun clear() { - kaliumPref.nuke() - } - -}