Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: notify user when sending first message in conversation on legal hold [WPB-4566] #2535

Merged
merged 9 commits into from
Dec 20, 2023
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.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 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 @@
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 @@
InvalidLinkDialogState.Hidden
)

private val shouldInformAboutDegradedBeforeSendingMessage = mutableStateOf(false)

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

init {
Expand All @@ -174,19 +177,12 @@
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 @@
}
}

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,

Check warning on line 247 in app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageComposerViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageComposerViewModel.kt#L246-L247

Added lines #L246 - L247 were not covered by tests
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 @@
}
}

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)

Check warning on line 503 in app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageComposerViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageComposerViewModel.kt#L503

Added line #L503 was not covered by tests

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
Loading