Skip to content

Commit

Permalink
feat: show legal hold disabled dialog [WPB-4870] (#2511)
Browse files Browse the repository at this point in the history
  • Loading branch information
saleniuk committed Dec 13, 2023
1 parent c5b8aa5 commit d11140e
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 1 deletion.
9 changes: 9 additions & 0 deletions app/src/main/kotlin/com/wire/android/ui/WireActivity.kt
Expand Up @@ -84,6 +84,9 @@ import com.wire.android.ui.home.E2EIRequiredDialog
import com.wire.android.ui.home.E2EISnoozeDialog
import com.wire.android.ui.home.appLock.LockCodeTimeManager
import com.wire.android.ui.home.sync.FeatureFlagNotificationViewModel
import com.wire.android.ui.legalhold.dialog.deactivated.LegalHoldDeactivatedDialog
import com.wire.android.ui.legalhold.dialog.deactivated.LegalHoldDeactivatedState
import com.wire.android.ui.legalhold.dialog.deactivated.LegalHoldDeactivatedViewModel
import com.wire.android.ui.legalhold.dialog.requested.LegalHoldRequestedDialog
import com.wire.android.ui.legalhold.dialog.requested.LegalHoldRequestedState
import com.wire.android.ui.legalhold.dialog.requested.LegalHoldRequestedViewModel
Expand Down Expand Up @@ -125,6 +128,7 @@ class WireActivity : AppCompatActivity() {

private val commonTopAppBarViewModel: CommonTopAppBarViewModel by viewModels()
private val legalHoldRequestedViewModel: LegalHoldRequestedViewModel by viewModels()
private val legalHoldDeactivatedViewModel: LegalHoldDeactivatedViewModel by viewModels()

val navigationCommands: MutableSharedFlow<NavigationCommand> = MutableSharedFlow()

Expand Down Expand Up @@ -306,6 +310,11 @@ class WireActivity : AppCompatActivity() {
acceptClicked = legalHoldRequestedViewModel::acceptClicked,
)
}
if (legalHoldDeactivatedViewModel.state is LegalHoldDeactivatedState.Visible) {
LegalHoldDeactivatedDialog(
dialogDismissed = legalHoldDeactivatedViewModel::dismiss,
)
}
if (showFileSharingDialog) {
FileRestrictionDialog(
isFileSharingEnabled = isFileSharingEnabledState,
Expand Down
@@ -0,0 +1,25 @@
/*
* 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.ui.legalhold.dialog.deactivated

import com.wire.kalium.logic.data.user.UserId

sealed class LegalHoldDeactivatedState {
data object Hidden : LegalHoldDeactivatedState()
data class Visible(val userId: UserId) : LegalHoldDeactivatedState()
}
@@ -0,0 +1,106 @@
/*
* 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.ui.legalhold.dialog.deactivated

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.wire.android.appLogger
import com.wire.android.di.KaliumCoreLogic
import com.wire.kalium.logic.CoreLogic
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.UserSessionScope
import com.wire.kalium.logic.feature.legalhold.LegalHoldState
import com.wire.kalium.logic.feature.legalhold.MarkLegalHoldChangeAsNotifiedForSelfUseCase
import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldChangeNotifiedForSelfUseCase
import com.wire.kalium.logic.feature.session.CurrentSessionResult
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class LegalHoldDeactivatedViewModel @Inject constructor(
@KaliumCoreLogic private val coreLogic: CoreLogic,
) : ViewModel() {

var state: LegalHoldDeactivatedState by mutableStateOf(LegalHoldDeactivatedState.Hidden)
private set

private fun <T> currentSessionFlow(noSession: T, session: suspend UserSessionScope.(UserId) -> Flow<T>): Flow<T> =
coreLogic.getGlobalScope().session.currentSessionFlow()
.flatMapLatest { currentSessionResult ->
when (currentSessionResult) {
is CurrentSessionResult.Failure.Generic -> {
appLogger.e("$TAG: Failed to get current session")
flowOf(noSession)
}

CurrentSessionResult.Failure.SessionNotFound -> flowOf(noSession)
is CurrentSessionResult.Success ->
currentSessionResult.accountInfo.userId.let { coreLogic.getSessionScope(it).session(it) }
}
}

init {
viewModelScope.launch {
currentSessionFlow(noSession = LegalHoldDeactivatedState.Hidden) { userId ->
observeLegalHoldChangeNotifiedForSelf()
.mapLatest {
when (it) {
is ObserveLegalHoldChangeNotifiedForSelfUseCase.Result.Failure -> {
appLogger.e("$TAG: Failed to get legal hold change notified data: ${it.failure}")
LegalHoldDeactivatedState.Hidden
}
ObserveLegalHoldChangeNotifiedForSelfUseCase.Result.AlreadyNotified -> LegalHoldDeactivatedState.Hidden
is ObserveLegalHoldChangeNotifiedForSelfUseCase.Result.ShouldNotify ->
when (it.legalHoldState) {
is LegalHoldState.Disabled -> LegalHoldDeactivatedState.Visible(userId)
is LegalHoldState.Enabled -> { // for enabled we don't show the dialog, just mark as already notified
coreLogic.getSessionScope(userId).markLegalHoldChangeAsNotifiedForSelf()
LegalHoldDeactivatedState.Hidden
}
}
}
}
}.collectLatest { state = it }
}
}

fun dismiss() {
viewModelScope.launch {
(state as? LegalHoldDeactivatedState.Visible)?.let {
coreLogic.getSessionScope(it.userId).markLegalHoldChangeAsNotifiedForSelf().let {
if (it is MarkLegalHoldChangeAsNotifiedForSelfUseCase.Result.Success) {
state = LegalHoldDeactivatedState.Hidden
}
}
}
}
}

companion object {
private const val TAG = "LegalHoldDeactivatedViewModel"
}
}
@@ -0,0 +1,137 @@
/*
* 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.ui.legalhold.dialog.deactivated

import com.wire.android.config.CoroutineTestExtension
import com.wire.android.ui.legalhold.dialog.deactivated.LegalHoldDeactivatedViewModelTest.Arrangement.Companion.UNKNOWN_ERROR
import com.wire.kalium.logic.CoreFailure
import com.wire.kalium.logic.CoreLogic
import com.wire.kalium.logic.data.auth.AccountInfo
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.legalhold.LegalHoldState
import com.wire.kalium.logic.feature.legalhold.MarkLegalHoldChangeAsNotifiedForSelfUseCase
import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldChangeNotifiedForSelfUseCase
import com.wire.kalium.logic.feature.session.CurrentSessionResult
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeInstanceOf
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@OptIn(ExperimentalCoroutinesApi::class)
@ExtendWith(CoroutineTestExtension::class)
class LegalHoldDeactivatedViewModelTest {

@Test
fun givenNoSession_whenGettingState_thenStateShouldBeHidden() = runTest {
val (_, viewModel) = Arrangement()
.withNotCurrentSession()
.arrange()
advanceUntilIdle()
viewModel.state shouldBeInstanceOf LegalHoldDeactivatedState.Hidden::class
}
@Test
fun givenSessionReturnsFailure_whenGettingState_thenStateShouldBeHidden() = runTest {
val (_, viewModel) = Arrangement()
.withCurrentSessionFailure()
.arrange()
advanceUntilIdle()
viewModel.state shouldBeInstanceOf LegalHoldDeactivatedState.Hidden::class
}
@Test
fun givenLegalHoldRequestReturnsFailure_whenGettingState_thenStateShouldBeHidden() = runTest {
val (_, viewModel) = Arrangement()
.withCurrentSessionExists()
.withLegalHoldChangeNotifiedResult(ObserveLegalHoldChangeNotifiedForSelfUseCase.Result.Failure(UNKNOWN_ERROR))
.arrange()
advanceUntilIdle()
viewModel.state shouldBeInstanceOf LegalHoldDeactivatedState.Hidden::class
}
@Test
fun givenAlreadyNotified_whenGettingState_thenStateShouldBeHidden() = runTest {
val (_, viewModel) = Arrangement()
.withCurrentSessionExists()
.withLegalHoldChangeNotifiedResult(ObserveLegalHoldChangeNotifiedForSelfUseCase.Result.AlreadyNotified)
.arrange()
advanceUntilIdle()
viewModel.state shouldBeInstanceOf LegalHoldDeactivatedState.Hidden::class
}
@Test
fun givenShouldNotify_whenGettingState_thenStateShouldBeVisible() = runTest {
val legalHoldState = LegalHoldState.Disabled
val (_, viewModel) = Arrangement()
.withCurrentSessionExists()
.withLegalHoldChangeNotifiedResult(ObserveLegalHoldChangeNotifiedForSelfUseCase.Result.ShouldNotify(legalHoldState))
.arrange()
advanceUntilIdle()
viewModel.state shouldBeInstanceOf LegalHoldDeactivatedState.Visible::class
}
@Test
fun givenShouldNotify_whenDismissing_thenStateShouldBeChangedToHidden() = runTest {
val legalHoldState = LegalHoldState.Disabled
val (arrangement, viewModel) = Arrangement()
.withCurrentSessionExists()
.withLegalHoldChangeNotifiedResult(ObserveLegalHoldChangeNotifiedForSelfUseCase.Result.ShouldNotify(legalHoldState))
.withMarkLegalHoldChangeAsNotifiedResult(MarkLegalHoldChangeAsNotifiedForSelfUseCase.Result.Success)
.arrange()
advanceUntilIdle()
viewModel.dismiss()
advanceUntilIdle()
viewModel.state shouldBeInstanceOf LegalHoldDeactivatedState.Hidden::class
coVerify { arrangement.coreLogic.getSessionScope(any()).markLegalHoldChangeAsNotifiedForSelf() }
}

private class Arrangement {

@MockK
lateinit var coreLogic: CoreLogic
val viewModel by lazy { LegalHoldDeactivatedViewModel(coreLogic) }

init { MockKAnnotations.init(this) }
fun withNotCurrentSession() = apply {
every { coreLogic.globalScope { session.currentSessionFlow() } } returns
flowOf(CurrentSessionResult.Failure.SessionNotFound)
}
fun withCurrentSessionFailure() = apply {
every { coreLogic.globalScope { session.currentSessionFlow() } } returns
flowOf(CurrentSessionResult.Failure.Generic(UNKNOWN_ERROR))
}
fun withCurrentSessionExists() = apply {
every { coreLogic.globalScope { session.currentSessionFlow() } } returns
flowOf(CurrentSessionResult.Success(AccountInfo.Valid(UserId("userId", "domain"))))
}
fun withLegalHoldChangeNotifiedResult(result: ObserveLegalHoldChangeNotifiedForSelfUseCase.Result) = apply {
coEvery { coreLogic.getSessionScope(any()).observeLegalHoldChangeNotifiedForSelf() } returns flowOf(result)
}
fun withMarkLegalHoldChangeAsNotifiedResult(result: MarkLegalHoldChangeAsNotifiedForSelfUseCase.Result) = apply {
coEvery { coreLogic.getSessionScope(any()).markLegalHoldChangeAsNotifiedForSelf() } returns result
}
fun arrange() = this to viewModel

companion object {
val UNKNOWN_ERROR = CoreFailure.Unknown(RuntimeException("error"))
}
}
}

0 comments on commit d11140e

Please sign in to comment.