Skip to content

Commit

Permalink
feat: notify user when sending first message in conversation on legal…
Browse files Browse the repository at this point in the history
… hold [WPB-4566] (#2535)
  • Loading branch information
saleniuk authored Dec 20, 2023
1 parent 2871638 commit d2f867e
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ import com.wire.kalium.logic.feature.conversation.ObserveConversationListDetails
import com.wire.kalium.logic.feature.conversation.ObserveConversationMembersUseCase
import com.wire.kalium.logic.feature.conversation.ObserveDegradedConversationNotifiedUseCase
import com.wire.kalium.logic.feature.conversation.ObserveIsSelfUserMemberUseCase
import com.wire.kalium.logic.feature.conversation.ObserveConversationUnderLegalHoldNotifiedUseCase
import com.wire.kalium.logic.feature.conversation.ObserveUserListByIdUseCase
import com.wire.kalium.logic.feature.conversation.ObserveUsersTypingUseCase
import com.wire.kalium.logic.feature.conversation.RefreshConversationsWithoutMetadataUseCase
import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase
import com.wire.kalium.logic.feature.conversation.RenameConversationUseCase
import com.wire.kalium.logic.feature.conversation.SendTypingEventUseCase
import com.wire.kalium.logic.feature.conversation.SetNotifiedAboutConversationUnderLegalHoldUseCase
import com.wire.kalium.logic.feature.conversation.SetUserInformedAboutVerificationUseCase
import com.wire.kalium.logic.feature.conversation.UpdateConversationAccessRoleUseCase
import com.wire.kalium.logic.feature.conversation.UpdateConversationArchivedStatusUseCase
Expand Down Expand Up @@ -274,4 +276,16 @@ class ConversationModule {
conversationScope: ConversationScope
): ObserveDegradedConversationNotifiedUseCase =
conversationScope.observeInformAboutVerificationBeforeMessagingFlagUseCase

@ViewModelScoped
@Provides
fun provideSetUserNotifiedAboutConversationUnderLegalHoldUseCase(
conversationScope: ConversationScope,
): SetNotifiedAboutConversationUnderLegalHoldUseCase = conversationScope.setNotifiedAboutConversationUnderLegalHold

@ViewModelScoped
@Provides
fun provideObserveLegalHoldWithChangeNotifiedForConversationUseCase(
conversationScope: ConversationScope,
): ObserveConversationUnderLegalHoldNotifiedUseCase = conversationScope.observeConversationUnderLegalHoldNotified
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ import com.wire.android.ui.common.WireDialog
import com.wire.android.ui.common.WireDialogButtonProperties
import com.wire.android.ui.common.WireDialogButtonType
import com.wire.android.ui.home.conversations.SureAboutMessagingDialogState
import com.wire.android.ui.home.messagecomposer.state.MessageBundle

@Composable
fun SureAboutMessagingInDegradedConversationDialog(
dialogState: SureAboutMessagingDialogState,
sendAnyway: (MessageBundle) -> Unit,
sendAnyway: () -> Unit,
hideDialog: () -> Unit
) {
if (dialogState is SureAboutMessagingDialogState.ConversationVerificationDegraded) {
if (dialogState is SureAboutMessagingDialogState.Visible.ConversationVerificationDegraded) {
WireDialog(
title = stringResource(R.string.sure_about_messaging_dialog_title),
text = stringResource(R.string.sure_about_messaging_dialog_body),
Expand All @@ -42,11 +41,11 @@ fun SureAboutMessagingInDegradedConversationDialog(
optionButton1Properties = WireDialogButtonProperties(
text = stringResource(R.string.sure_about_messaging_dialog_positiv_button),
type = WireDialogButtonType.Primary,
onClick = { sendAnyway(dialogState.messageBundleToSend) }
onClick = sendAnyway,
),
dismissButtonProperties = WireDialogButtonProperties(
text = stringResource(R.string.label_cancel),
onClick = hideDialog
onClick = hideDialog,
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ import com.wire.android.ui.home.messagecomposer.MessageComposer
import com.wire.android.ui.home.messagecomposer.state.MessageBundle
import com.wire.android.ui.home.messagecomposer.state.MessageComposerStateHolder
import com.wire.android.ui.home.messagecomposer.state.rememberMessageComposerStateHolder
import com.wire.android.ui.legalhold.dialog.subject.LegalHoldSubjectMessageDialog
import com.wire.android.ui.theme.wireColorScheme
import com.wire.android.util.extension.openAppInfoScreen
import com.wire.android.util.normalizeLink
Expand Down Expand Up @@ -430,10 +431,18 @@ fun ConversationScreen(

SureAboutMessagingInDegradedConversationDialog(
dialogState = messageComposerViewModel.sureAboutMessagingDialogState,
sendAnyway = messageComposerViewModel::sureAboutSendingMessage,
hideDialog = messageComposerViewModel::hideSureAboutSendingMessage
sendAnyway = messageComposerViewModel::acceptSureAboutSendingMessage,
hideDialog = messageComposerViewModel::dismissSureAboutSendingMessage
)

(messageComposerViewModel.sureAboutMessagingDialogState as? SureAboutMessagingDialogState.Visible.ConversationUnderLegalHold)?.let {
LegalHoldSubjectMessageDialog(
conversationName = conversationInfoViewModel.conversationInfoViewState.conversationName.asString(),
dialogDismissed = messageComposerViewModel::dismissSureAboutSendingMessage,
sendAnywayClicked = messageComposerViewModel::acceptSureAboutSendingMessage,
)
}

groupDetailsScreenResultRecipient.onNavResult { result ->
when (result) {
is Canceled -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ import com.wire.kalium.logic.feature.conversation.IsInteractionAvailableResult
import com.wire.kalium.logic.feature.conversation.MembersToMentionUseCase
import com.wire.kalium.logic.feature.conversation.ObserveConversationInteractionAvailabilityUseCase
import com.wire.kalium.logic.feature.conversation.ObserveDegradedConversationNotifiedUseCase
import com.wire.kalium.logic.feature.conversation.ObserveConversationUnderLegalHoldNotifiedUseCase
import com.wire.kalium.logic.feature.conversation.SendTypingEventUseCase
import com.wire.kalium.logic.feature.conversation.SetNotifiedAboutConversationUnderLegalHoldUseCase
import com.wire.kalium.logic.feature.conversation.SetUserInformedAboutVerificationUseCase
import com.wire.kalium.logic.feature.conversation.UpdateConversationReadDateUseCase
import com.wire.kalium.logic.feature.message.DeleteMessageUseCase
Expand All @@ -77,6 +79,7 @@ import com.wire.kalium.logic.functional.onFailure
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.datetime.Instant
Expand Down Expand Up @@ -110,7 +113,9 @@ class MessageComposerViewModel @Inject constructor(
private val imageUtil: ImageUtil,
private val fileManager: FileManager,
private val setUserInformedAboutVerification: SetUserInformedAboutVerificationUseCase,
private val observeDegradedConversationNotified: ObserveDegradedConversationNotifiedUseCase
private val observeDegradedConversationNotified: ObserveDegradedConversationNotifiedUseCase,
private val setNotifiedAboutConversationUnderLegalHold: SetNotifiedAboutConversationUnderLegalHoldUseCase,
private val observeConversationUnderLegalHoldNotified: ObserveConversationUnderLegalHoldNotifiedUseCase,
) : SavedStateViewModel(savedStateHandle) {

var messageComposerViewState = mutableStateOf(MessageComposerViewState())
Expand Down Expand Up @@ -162,10 +167,8 @@ class MessageComposerViewModel @Inject constructor(
InvalidLinkDialogState.Hidden
)

private val shouldInformAboutDegradedBeforeSendingMessage = mutableStateOf(false)

var sureAboutMessagingDialogState: SureAboutMessagingDialogState by mutableStateOf(
SureAboutMessagingDialogState.None
SureAboutMessagingDialogState.Hidden
)

init {
Expand All @@ -174,19 +177,12 @@ class MessageComposerViewModel @Inject constructor(
observeIsTypingAvailable()
observeSelfDeletingMessagesStatus()
setFileSharingStatus()
observeInformedAboutDegradedVerification()
}

private fun onSnackbarMessage(type: SnackBarMessage) = viewModelScope.launch {
_infoMessage.emit(type)
}

private fun observeInformedAboutDegradedVerification() = viewModelScope.launch {
observeDegradedConversationNotified(conversationId).collect {
shouldInformAboutDegradedBeforeSendingMessage.value = !it
}
}

private fun observeIsTypingAvailable() = viewModelScope.launch {
observeConversationInteractionAvailability(conversationId).collect { result ->
messageComposerViewState.value = messageComposerViewState.value.copy(
Expand All @@ -208,58 +204,66 @@ class MessageComposerViewModel @Inject constructor(
}
}

private suspend fun shouldInformAboutDegradedBeforeSendingMessage(): Boolean =
observeDegradedConversationNotified(conversationId).first().let { !it }

private suspend fun shouldInformAboutUnderLegalHoldBeforeSendingMessage() =
observeConversationUnderLegalHoldNotified(conversationId).first().let { !it }

fun trySendMessage(messageBundle: MessageBundle) {
if (shouldInformAboutDegradedBeforeSendingMessage.value) {
sureAboutMessagingDialogState = SureAboutMessagingDialogState.ConversationVerificationDegraded(messageBundle)
} else {
sendMessage(messageBundle)
viewModelScope.launch {
when {
shouldInformAboutDegradedBeforeSendingMessage() ->
sureAboutMessagingDialogState = SureAboutMessagingDialogState.Visible.ConversationVerificationDegraded(messageBundle)
shouldInformAboutUnderLegalHoldBeforeSendingMessage() ->
sureAboutMessagingDialogState = SureAboutMessagingDialogState.Visible.ConversationUnderLegalHold(messageBundle)
else -> sendMessage(messageBundle)
}
}
}

private fun sendMessage(messageBundle: MessageBundle) {
viewModelScope.launch {
when (messageBundle) {
is ComposableMessageBundle.EditMessageBundle -> {
with(messageBundle) {
sendEditTextMessage(
conversationId = conversationId,
originalMessageId = originalMessageId,
text = newContent,
mentions = newMentions.map { it.intoMessageMention() },
)
}
sendTypingEvent(conversationId, TypingIndicatorMode.STOPPED)
}

is ComposableMessageBundle.AttachmentPickedBundle -> {
handleAssetMessageBundle(
attachmentUri = messageBundle.attachmentUri
private suspend fun sendMessage(messageBundle: MessageBundle) {
when (messageBundle) {
is ComposableMessageBundle.EditMessageBundle -> {
with(messageBundle) {
sendEditTextMessage(
conversationId = conversationId,
originalMessageId = originalMessageId,
text = newContent,
mentions = newMentions.map { it.intoMessageMention() },
)
}
sendTypingEvent(conversationId, TypingIndicatorMode.STOPPED)
}

is ComposableMessageBundle.AudioMessageBundle -> {
handleAssetMessageBundle(
attachmentUri = messageBundle.attachmentUri,
audioPath = messageBundle.attachmentUri.uri.path?.toPath()
)
}
is ComposableMessageBundle.AttachmentPickedBundle -> {
handleAssetMessageBundle(
attachmentUri = messageBundle.attachmentUri
)
}

is ComposableMessageBundle.SendTextMessageBundle -> {
with(messageBundle) {
sendTextMessage(
conversationId = conversationId,
text = message,
mentions = mentions.map { it.intoMessageMention() },
quotedMessageId = quotedMessageId
)
}
sendTypingEvent(conversationId, TypingIndicatorMode.STOPPED)
}
is ComposableMessageBundle.AudioMessageBundle -> {
handleAssetMessageBundle(
attachmentUri = messageBundle.attachmentUri,
audioPath = messageBundle.attachmentUri.uri.path?.toPath()
)
}

Ping -> {
pingRinger.ping(R.raw.ping_from_me, isReceivingPing = false)
sendKnockUseCase(conversationId = conversationId, hotKnock = false)
is ComposableMessageBundle.SendTextMessageBundle -> {
with(messageBundle) {
sendTextMessage(
conversationId = conversationId,
text = message,
mentions = mentions.map { it.intoMessageMention() },
quotedMessageId = quotedMessageId
)
}
sendTypingEvent(conversationId, TypingIndicatorMode.STOPPED)
}

Ping -> {
pingRinger.ping(R.raw.ping_from_me, isReceivingPing = false)
sendKnockUseCase(conversationId = conversationId, hotKnock = false)
}
}
}
Expand Down Expand Up @@ -473,16 +477,34 @@ class MessageComposerViewModel @Inject constructor(
}
}

fun sureAboutSendingMessage(messageBundle: MessageBundle) {
hideSureAboutSendingMessage()
sendMessage(messageBundle)
fun acceptSureAboutSendingMessage() {
(sureAboutMessagingDialogState as? SureAboutMessagingDialogState.Visible)?.let {
viewModelScope.launch {
it.markAsNotified()
trySendMessage(it.messageBundleToSend)
}
}
}

fun hideSureAboutSendingMessage() {
sureAboutMessagingDialogState = SureAboutMessagingDialogState.None
viewModelScope.launch {
setUserInformedAboutVerification.invoke(conversationId)
fun dismissSureAboutSendingMessage() {
(sureAboutMessagingDialogState as? SureAboutMessagingDialogState.Visible)?.let {
viewModelScope.launch {
it.markAsNotified()
}
}
}

private suspend fun SureAboutMessagingDialogState.markAsNotified() {
when (this) {
is SureAboutMessagingDialogState.Visible.ConversationUnderLegalHold ->
setNotifiedAboutConversationUnderLegalHold(conversationId)

is SureAboutMessagingDialogState.Visible.ConversationVerificationDegraded ->
setUserInformedAboutVerification(conversationId)

SureAboutMessagingDialogState.Hidden -> { /* do nothing */ }
}
sureAboutMessagingDialogState = SureAboutMessagingDialogState.Hidden
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ sealed class InvalidLinkDialogState {
}

sealed class SureAboutMessagingDialogState {
object None : SureAboutMessagingDialogState()
data class ConversationVerificationDegraded(val messageBundleToSend: MessageBundle) : SureAboutMessagingDialogState()
data object Hidden : SureAboutMessagingDialogState()
sealed class Visible(open val messageBundleToSend: MessageBundle) : SureAboutMessagingDialogState() {
data class ConversationVerificationDegraded(override val messageBundleToSend: MessageBundle) : Visible(messageBundleToSend)
data class ConversationUnderLegalHold(override val messageBundleToSend: MessageBundle) : Visible(messageBundleToSend)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@
*/
package com.wire.android.ui.legalhold.dialog.subject

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
Expand All @@ -33,22 +29,21 @@ import com.wire.android.ui.common.WireDialogButtonType
import com.wire.android.ui.legalhold.dialog.common.LearnMoreAboutLegalHoldButton
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun LegalHoldSubjectBaseDialog(
name: String,
isConversation: Boolean,
customInfo: String? = null,
withDefaultInfo: Boolean,
cancelText: String,
dialogDismissed: () -> Unit,
action: Pair<String, () -> Unit>? = null,
bottomDescriptionText: String? = null,
) {
val text = stringResource(id = R.string.legal_hold_subject_dialog_description).let {
if (isConversation) stringResource(id = R.string.legal_hold_subject_dialog_description_group) + "\n\n" + it
else it
}
val text = listOfNotNull(
customInfo,
if (withDefaultInfo) stringResource(id = R.string.legal_hold_subject_dialog_description) else null
).joinToString("\n\n")
WireDialog(
title = stringResource(id = R.string.legal_hold_subject_dialog_title, name),
text = text,
Expand All @@ -67,26 +62,16 @@ fun LegalHoldSubjectBaseDialog(
)
},
) {
Column(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.wireDimensions.dialogTextsSpacing),
LearnMoreAboutLegalHoldButton(
modifier = Modifier.padding(bottom = MaterialTheme.wireDimensions.dialogTextsSpacing)
) {
LearnMoreAboutLegalHoldButton()
if (!bottomDescriptionText.isNullOrEmpty()) {
Text(
text = bottomDescriptionText,
style = MaterialTheme.wireTypography.body01,
modifier = Modifier.fillMaxWidth()
)
}
}
)
}
}

@Composable
@PreviewMultipleThemes
fun PreviewLegalHoldSubjectBaseDialog() {
WireTheme {
LegalHoldSubjectBaseDialog("username", true, "cancel", {}, Pair("send anyway", {}), "Send anyway?")
LegalHoldSubjectBaseDialog("username", null, true, "cancel", {}, Pair("send anyway", {}))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fun LegalHoldSubjectConnectionDialog(
) {
LegalHoldSubjectBaseDialog(
name = userName,
isConversation = false,
withDefaultInfo = true,
cancelText = stringResource(id = R.string.label_cancel),
dialogDismissed = dialogDismissed,
action = stringResource(id = R.string.connection_label_connect) to connectClicked,
Expand Down
Loading

0 comments on commit d2f867e

Please sign in to comment.