diff --git a/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt b/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt index 5f2bb410f10..58d12d5bf16 100644 --- a/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt +++ b/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt @@ -121,6 +121,8 @@ import com.wire.kalium.logic.feature.user.ObserveValidAccountsUseCase import com.wire.kalium.logic.feature.user.SelfServerConfigUseCase import com.wire.kalium.logic.feature.user.UpdateDisplayNameUseCase import com.wire.kalium.logic.feature.user.UpdateEmailUseCase +import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigUseCase +import com.wire.kalium.logic.feature.user.screenshotCensoring.PersistScreenshotCensoringConfigUseCase import com.wire.kalium.logic.featureFlags.KaliumConfigs import dagger.Module import dagger.Provides @@ -1199,4 +1201,18 @@ class UseCaseModule { @CurrentAccount currentAccount: UserId ): DeleteAccountUseCase = coreLogic.getSessionScope(currentAccount).users.deleteAccount + + @ViewModelScoped + @Provides + fun providePersistScreenshotCensoringConfigUseCase( + @KaliumCoreLogic coreLogic: CoreLogic, + @CurrentAccount currentAccount: UserId + ): PersistScreenshotCensoringConfigUseCase = coreLogic.getSessionScope(currentAccount).persistScreenshotCensoringConfig + + @ViewModelScoped + @Provides + fun provideObserveScreenshotCensoringConfigUseCase( + @KaliumCoreLogic coreLogic: CoreLogic, + @CurrentAccount currentAccount: UserId + ): ObserveScreenshotCensoringConfigUseCase = coreLogic.getSessionScope(currentAccount).observeScreenshotCensoringConfig } diff --git a/app/src/main/kotlin/com/wire/android/di/ObserveScreenshotCensoringConfigUseCaseProvider.kt b/app/src/main/kotlin/com/wire/android/di/ObserveScreenshotCensoringConfigUseCaseProvider.kt new file mode 100644 index 00000000000..5ede4b40d05 --- /dev/null +++ b/app/src/main/kotlin/com/wire/android/di/ObserveScreenshotCensoringConfigUseCaseProvider.kt @@ -0,0 +1,38 @@ +/* + * Wire + * Copyright (C) 2023 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.android.di + +import com.wire.kalium.logic.CoreLogic +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigUseCase +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class ObserveScreenshotCensoringConfigUseCaseProvider @AssistedInject constructor( + @KaliumCoreLogic private val coreLogic: CoreLogic, + @Assisted private val userId: UserId +) { + val observeScreenshotCensoringConfig: ObserveScreenshotCensoringConfigUseCase + get() = coreLogic.getSessionScope(userId).observeScreenshotCensoringConfig + + @AssistedFactory + interface Factory { + fun create(userId: UserId): ObserveScreenshotCensoringConfigUseCaseProvider + } +} diff --git a/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt b/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt index c15fbacf7c3..bdf981afa78 100644 --- a/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt +++ b/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt @@ -20,9 +20,11 @@ package com.wire.android.ui +import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle +import android.view.WindowManager import androidx.activity.compose.setContent import androidx.activity.viewModels import androidx.annotation.StringRes @@ -37,6 +39,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource @@ -137,7 +140,8 @@ class WireActivity : AppCompatActivity() { LocalFeatureVisibilityFlags provides FeatureVisibilityFlags, LocalSyncStateObserver provides SyncStateObserver(viewModel.observeSyncFlowState), LocalCustomUiConfigurationProvider provides CustomUiConfigurationProvider, - LocalSnackbarHostState provides snackbarHostState + LocalSnackbarHostState provides snackbarHostState, + LocalActivity provides this ) { WireTheme { Column { @@ -149,6 +153,7 @@ class WireActivity : AppCompatActivity() { startDestination = startDestination, onComplete = onComplete ) + handleScreenshotCensoring() handleDialogs() } } @@ -209,6 +214,17 @@ class WireActivity : AppCompatActivity() { } } + @Composable + private fun handleScreenshotCensoring() { + LaunchedEffect(viewModel.globalAppState.screenshotCensoringEnabled) { + if (viewModel.globalAppState.screenshotCensoringEnabled) { + window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) + } + } + } + @Composable private fun handleDialogs() { updateAppDialog({ updateTheApp() }, viewModel.globalAppState.updateAppDialog) @@ -436,3 +452,7 @@ class WireActivity : AppCompatActivity() { private const val HANDLED_DEEPLINK_FLAG = "deeplink_handled_flag_key" } } + +val LocalActivity = staticCompositionLocalOf { + error("No Activity provided") +} diff --git a/app/src/main/kotlin/com/wire/android/ui/WireActivityViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/WireActivityViewModel.kt index ed31bcf403e..3c74b8abfd7 100644 --- a/app/src/main/kotlin/com/wire/android/ui/WireActivityViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/WireActivityViewModel.kt @@ -30,6 +30,7 @@ import com.wire.android.BuildConfig import com.wire.android.appLogger import com.wire.android.di.AuthServerConfigProvider import com.wire.android.di.KaliumCoreLogic +import com.wire.android.di.ObserveScreenshotCensoringConfigUseCaseProvider import com.wire.android.di.ObserveSyncStateUseCaseProvider import com.wire.android.feature.AccountSwitchUseCase import com.wire.android.feature.SwitchAccountParam @@ -69,6 +70,7 @@ import com.wire.kalium.logic.feature.session.CurrentSessionFlowUseCase import com.wire.kalium.logic.feature.session.CurrentSessionResult import com.wire.kalium.logic.feature.session.GetAllSessionsResult import com.wire.kalium.logic.feature.session.GetSessionsUseCase +import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigResult import com.wire.kalium.logic.feature.user.webSocketStatus.ObservePersistentWebSocketConnectionStatusUseCase import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString import dagger.hilt.android.lifecycle.HiltViewModel @@ -109,6 +111,7 @@ class WireActivityViewModel @Inject constructor( private val observeNewClients: ObserveNewClientsUseCase, private val clearNewClientsForUser: ClearNewClientsForUserUseCase, private val currentScreenManager: CurrentScreenManager, + private val observeScreenshotCensoringConfigUseCaseProviderFactory: ObserveScreenshotCensoringConfigUseCaseProvider.Factory, ) : ViewModel() { var globalAppState: GlobalAppState by mutableStateOf(GlobalAppState()) @@ -138,6 +141,13 @@ class WireActivityViewModel @Inject constructor( val observeSyncFlowState: StateFlow = _observeSyncFlowState init { + observeSyncState() + observeUpdateAppState() + observeNewClientState() + observeScreenshotCensoringConfigState() + } + + private fun observeSyncState() { viewModelScope.launch(dispatchers.io()) { observeUserId .flatMapLatest { @@ -146,6 +156,9 @@ class WireActivityViewModel @Inject constructor( .distinctUntilChanged() .collect { _observeSyncFlowState.emit(it) } } + } + + private fun observeUpdateAppState() { viewModelScope.launch(dispatchers.io()) { observeIfAppUpdateRequired(BuildConfig.VERSION_CODE) .distinctUntilChanged() @@ -153,6 +166,9 @@ class WireActivityViewModel @Inject constructor( globalAppState = globalAppState.copy(updateAppDialog = it) } } + } + + private fun observeNewClientState() { viewModelScope.launch(dispatchers.io()) { currentScreenManager.observeCurrentScreen(this) .flatMapLatest { @@ -166,6 +182,21 @@ class WireActivityViewModel @Inject constructor( } } + private fun observeScreenshotCensoringConfigState() { + viewModelScope.launch(dispatchers.io()) { + observeUserId + .flatMapLatest { + it?.let { + observeScreenshotCensoringConfigUseCaseProviderFactory.create(it).observeScreenshotCensoringConfig() + } ?: flowOf(ObserveScreenshotCensoringConfigResult.Disabled) + }.collect { + globalAppState = globalAppState.copy( + screenshotCensoringEnabled = it is ObserveScreenshotCensoringConfigResult.Enabled + ) + } + } + } + private suspend fun handleInvalidSession(logoutReason: LogoutReason) { withContext(dispatchers.main()) { when (logoutReason) { @@ -527,5 +558,6 @@ data class GlobalAppState( val blockUserUI: CurrentSessionErrorState? = null, val updateAppDialog: Boolean = false, val conversationJoinedDialog: JoinConversationViaCodeState? = null, - val newClientDialog: NewClientsData? = null + val newClientDialog: NewClientsData? = null, + val screenshotCensoringEnabled: Boolean = true, ) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModel.kt index 8c024184565..fca36a2e336 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModel.kt @@ -53,7 +53,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import javax.inject.Inject -@Suppress("LongParameterList") +@Suppress("LongParameterList", "TooManyFunctions") @HiltViewModel class ConversationInfoViewModel @Inject constructor( private val qualifiedIdMapper: QualifiedIdMapper, @@ -74,6 +74,10 @@ class ConversationInfoViewModel @Inject constructor( private lateinit var selfUserId: UserId init { + getSelfUserId() + } + + private fun getSelfUserId() { viewModelScope.launch { selfUserId = observerSelfUser().first().id } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewState.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewState.kt index d09835bfb66..6a4146dc59a 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewState.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewState.kt @@ -33,7 +33,7 @@ data class ConversationInfoViewState( val conversationDetailsData: ConversationDetailsData = ConversationDetailsData.None, val conversationAvatar: ConversationAvatar = ConversationAvatar.None, val hasUserPermissionToEdit: Boolean = false, - val conversationType: Conversation.Type = Conversation.Type.ONE_ON_ONE + val conversationType: Conversation.Type = Conversation.Type.ONE_ON_ONE, ) sealed class ConversationDetailsData { diff --git a/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsScreen.kt index 83f1ffd9c61..8e5ba950032 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsScreen.kt @@ -44,6 +44,8 @@ fun PrivacySettingsConfigScreen( PrivacySettingsScreenContent( isReadReceiptsEnabled = state.isReadReceiptsEnabled, setReadReceiptsState = ::setReadReceiptsState, + screenshotCensoringConfig = state.screenshotCensoringConfig, + setScreenshotCensoringConfig = ::setScreenshotCensoringConfig, onBackPressed = ::navigateBack ) } @@ -53,6 +55,8 @@ fun PrivacySettingsConfigScreen( fun PrivacySettingsScreenContent( isReadReceiptsEnabled: Boolean, setReadReceiptsState: (Boolean) -> Unit, + screenshotCensoringConfig: ScreenshotCensoringConfig, + setScreenshotCensoringConfig: (Boolean) -> Unit, onBackPressed: () -> Unit ) { Scaffold(topBar = { @@ -73,6 +77,26 @@ fun PrivacySettingsScreenContent( arrowType = ArrowType.NONE, subtitle = stringResource(id = R.string.settings_send_read_receipts_description) ) + GroupConversationOptionsItem( + title = stringResource(R.string.settings_censor_screenshots), + switchState = when (screenshotCensoringConfig) { + ScreenshotCensoringConfig.DISABLED -> + SwitchState.Enabled(value = false, onCheckedChange = setScreenshotCensoringConfig) + + ScreenshotCensoringConfig.ENABLED_BY_USER -> + SwitchState.Enabled(value = true, onCheckedChange = setScreenshotCensoringConfig) + + ScreenshotCensoringConfig.ENFORCED_BY_TEAM -> + SwitchState.Disabled(value = true) + }, + arrowType = ArrowType.NONE, + subtitle = stringResource( + id = when (screenshotCensoringConfig) { + ScreenshotCensoringConfig.ENFORCED_BY_TEAM -> R.string.settings_censor_screenshots_enforced_by_team_description + else -> R.string.settings_censor_screenshots_description + } + ) + ) } } } @@ -80,5 +104,5 @@ fun PrivacySettingsScreenContent( @Composable @Preview fun PreviewSendReadReceipts() { - PrivacySettingsScreenContent(true, {}, {}) + PrivacySettingsScreenContent(true, {}, ScreenshotCensoringConfig.DISABLED, {}, {}) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsState.kt b/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsState.kt index a137acbcac4..92e7473d987 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsState.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsState.kt @@ -22,4 +22,9 @@ package com.wire.android.ui.home.settings.privacy data class PrivacySettingsState( val isReadReceiptsEnabled: Boolean = true, + val screenshotCensoringConfig: ScreenshotCensoringConfig = ScreenshotCensoringConfig.ENABLED_BY_USER ) + +enum class ScreenshotCensoringConfig { + DISABLED, ENABLED_BY_USER, ENFORCED_BY_TEAM +} diff --git a/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsViewModel.kt index 6811c7da27b..bf1928170b3 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/settings/privacy/PrivacySettingsViewModel.kt @@ -31,7 +31,12 @@ import com.wire.android.util.dispatchers.DispatcherProvider import com.wire.kalium.logic.feature.user.readReceipts.ObserveReadReceiptsEnabledUseCase import com.wire.kalium.logic.feature.user.readReceipts.PersistReadReceiptsStatusConfigUseCase import com.wire.kalium.logic.feature.user.readReceipts.ReadReceiptStatusConfigResult +import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigResult +import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigUseCase +import com.wire.kalium.logic.feature.user.screenshotCensoring.PersistScreenshotCensoringConfigResult +import com.wire.kalium.logic.feature.user.screenshotCensoring.PersistScreenshotCensoringConfigUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import javax.inject.Inject @@ -42,6 +47,8 @@ class PrivacySettingsViewModel @Inject constructor( private val dispatchers: DispatcherProvider, private val persistReadReceiptsStatusConfig: PersistReadReceiptsStatusConfigUseCase, private val observeReadReceiptsEnabled: ObserveReadReceiptsEnabledUseCase, + private val persistScreenshotCensoringConfig: PersistScreenshotCensoringConfigUseCase, + private val observeScreenshotCensoringConfig: ObserveScreenshotCensoringConfigUseCase ) : ViewModel() { var state by mutableStateOf(PrivacySettingsState()) @@ -49,8 +56,24 @@ class PrivacySettingsViewModel @Inject constructor( init { viewModelScope.launch { - observeReadReceiptsEnabled().collect { - state = state.copy(isReadReceiptsEnabled = it) + combine( + observeReadReceiptsEnabled(), + observeScreenshotCensoringConfig(), + ::Pair + ).collect { (readReceiptsEnabled, screenshotCensoringConfig) -> + state = state.copy( + isReadReceiptsEnabled = readReceiptsEnabled, + screenshotCensoringConfig = when (screenshotCensoringConfig) { + ObserveScreenshotCensoringConfigResult.Disabled -> + ScreenshotCensoringConfig.DISABLED + + ObserveScreenshotCensoringConfigResult.Enabled.ChosenByUser -> + ScreenshotCensoringConfig.ENABLED_BY_USER + + ObserveScreenshotCensoringConfigResult.Enabled.EnforcedByTeamSelfDeletingSettings -> + ScreenshotCensoringConfig.ENFORCED_BY_TEAM + } + ) } } } @@ -73,4 +96,18 @@ class PrivacySettingsViewModel @Inject constructor( } } } + + fun setScreenshotCensoringConfig(isEnabled: Boolean) { + viewModelScope.launch { + when (persistScreenshotCensoringConfig(isEnabled)) { + is PersistScreenshotCensoringConfigResult.Failure -> { + appLogger.e("Something went wrong while updating screenshot censoring config") + } + + is PersistScreenshotCensoringConfigResult.Success -> { + appLogger.d("Screenshot censoring config changed") + } + } + } + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd28ed4432d..40cb53505f2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -847,6 +847,9 @@ Send read receipts If this is OFF, you won’t be able to see read receipts from other people. This setting does not apply to group conversations. + Censor screenshots + If this is ON, then the content of the messages will not be visible on the screenshot or screen recording. + This is enforced by the self-deleting message team setting and cannot be changed.\nThe content of the messages will not be visible on the screenshot or screen recording. Your Devices Current Device diff --git a/app/src/test/kotlin/com/wire/android/ui/WireActivityViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/WireActivityViewModelTest.kt index 461b9bd5de1..c6967e4ffcb 100644 --- a/app/src/test/kotlin/com/wire/android/ui/WireActivityViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/WireActivityViewModelTest.kt @@ -21,9 +21,11 @@ package com.wire.android.ui import android.content.Intent +import com.wire.android.config.CoroutineTestExtension import com.wire.android.config.TestDispatcherProvider import com.wire.android.config.mockUri import com.wire.android.di.AuthServerConfigProvider +import com.wire.android.di.ObserveScreenshotCensoringConfigUseCaseProvider import com.wire.android.di.ObserveSyncStateUseCaseProvider import com.wire.android.feature.AccountSwitchUseCase import com.wire.android.framework.TestClient @@ -58,6 +60,8 @@ import com.wire.kalium.logic.feature.server.GetServerConfigUseCase import com.wire.kalium.logic.feature.session.CurrentSessionFlowUseCase import com.wire.kalium.logic.feature.session.CurrentSessionResult import com.wire.kalium.logic.feature.session.GetSessionsUseCase +import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigResult +import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigUseCase import com.wire.kalium.logic.feature.user.webSocketStatus.ObservePersistentWebSocketConnectionStatusUseCase import com.wire.kalium.logic.sync.ObserveSyncStateUseCase import io.mockk.MockKAnnotations @@ -77,9 +81,11 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.amshove.kluent.internal.assertEquals import org.amshove.kluent.`should be equal to` -import org.junit.Test +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith @OptIn(ExperimentalCoroutinesApi::class) +@ExtendWith(CoroutineTestExtension::class) class WireActivityViewModelTest { @Test @@ -638,6 +644,46 @@ class WireActivityViewModelTest { coVerify(exactly = 1) { arrangement.clearNewClientsForUser(USER_ID) } } + @Test + fun `given session and screenshot censoring disabled, when observing it, then set state to false`() = runTest { + val (_, viewModel) = Arrangement() + .withSomeCurrentSession() + .withScreenshotCensoringConfig(ObserveScreenshotCensoringConfigResult.Disabled) + .arrange() + advanceUntilIdle() + assertEquals(false, viewModel.globalAppState.screenshotCensoringEnabled) + } + + @Test + fun `given session and screenshot censoring enabled by user, when observing it, then set state to true`() = runTest { + val (_, viewModel) = Arrangement() + .withSomeCurrentSession() + .withScreenshotCensoringConfig(ObserveScreenshotCensoringConfigResult.Enabled.ChosenByUser) + .arrange() + advanceUntilIdle() + assertEquals(true, viewModel.globalAppState.screenshotCensoringEnabled) + } + + @Test + fun `given session and screenshot censoring enforced by team, when observing it, then set state to true`() = runTest { + val (_, viewModel) = Arrangement() + .withSomeCurrentSession() + .withScreenshotCensoringConfig(ObserveScreenshotCensoringConfigResult.Enabled.EnforcedByTeamSelfDeletingSettings) + .arrange() + advanceUntilIdle() + assertEquals(true, viewModel.globalAppState.screenshotCensoringEnabled) + } + + @Test + fun `given no session, when observing screenshot censoring, then set state to false`() = runTest { + val (_, viewModel) = Arrangement() + .withNoCurrentSession() + .withScreenshotCensoringConfig(ObserveScreenshotCensoringConfigResult.Enabled.EnforcedByTeamSelfDeletingSettings) + .arrange() + advanceUntilIdle() + assertEquals(false, viewModel.globalAppState.screenshotCensoringEnabled) + } + private class Arrangement { init { // Tests setup @@ -655,6 +701,10 @@ class WireActivityViewModelTest { every { observeSyncStateUseCase() } returns emptyFlow() coEvery { observeIfAppUpdateRequired(any()) } returns flowOf(false) coEvery { observeNewClients() } returns flowOf() + every { observeScreenshotCensoringConfigUseCaseProviderFactory.create(any()).observeScreenshotCensoringConfig } returns + observeScreenshotCensoringConfigUseCase + coEvery { observeScreenshotCensoringConfigUseCase() } returns flowOf(ObserveScreenshotCensoringConfigResult.Disabled) + coEvery { currentScreenManager.observeCurrentScreen(any()) } returns MutableStateFlow(CurrentScreen.SomeOther) } @MockK @@ -704,6 +754,12 @@ class WireActivityViewModelTest { @MockK lateinit var currentScreenManager: CurrentScreenManager + @MockK + private lateinit var observeScreenshotCensoringConfigUseCase: ObserveScreenshotCensoringConfigUseCase + + @MockK + private lateinit var observeScreenshotCensoringConfigUseCaseProviderFactory: ObserveScreenshotCensoringConfigUseCaseProvider.Factory + private val viewModel by lazy { WireActivityViewModel( coreLogic = coreLogic, @@ -722,6 +778,7 @@ class WireActivityViewModelTest { observeNewClients = observeNewClients, clearNewClientsForUser = clearNewClientsForUser, currentScreenManager = currentScreenManager, + observeScreenshotCensoringConfigUseCaseProviderFactory = observeScreenshotCensoringConfigUseCaseProviderFactory ) } @@ -732,6 +789,7 @@ class WireActivityViewModelTest { fun withNoCurrentSession(): Arrangement { coEvery { currentSessionFlow() } returns flowOf(CurrentSessionResult.Failure.SessionNotFound) + coEvery { coreLogic.getGlobalScope().session.currentSession() } returns CurrentSessionResult.Failure.SessionNotFound return this } @@ -804,6 +862,10 @@ class WireActivityViewModelTest { coEvery { currentScreenManager.observeCurrentScreen(any()) } returns currentScreenFlow } + suspend fun withScreenshotCensoringConfig(result: ObserveScreenshotCensoringConfigResult) = apply { + coEvery { observeScreenshotCensoringConfigUseCase() } returns flowOf(result) + } + fun arrange() = this to viewModel } diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelArrangement.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelArrangement.kt index aee0badf9d1..5d5145b92c8 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelArrangement.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelArrangement.kt @@ -41,7 +41,6 @@ import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map - class ConversationInfoViewModelArrangement { val conversationId: ConversationId = ConversationId("some-dummy-value", "some.dummy.domain") diff --git a/kalium b/kalium index 5f13458e5cf..9379ce2f273 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 5f13458e5cf7054a02ce2458f83be94856cc1f53 +Subproject commit 9379ce2f27319237be400f7942c4c57c170b26e7