diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 4e6dc986087..62dfff08d3e 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -21,7 +21,7 @@ jobs: distribution: 'temurin' cache: gradle - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@8d49e559aae34d3e0eb16cde532684bc9702762b + uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 - name: Run Detekt run: | ./gradlew detektAll diff --git a/.github/workflows/gradle-run-ui-tests.yml b/.github/workflows/gradle-run-ui-tests.yml index d0e30568021..e1565f5cf48 100644 --- a/.github/workflows/gradle-run-ui-tests.yml +++ b/.github/workflows/gradle-run-ui-tests.yml @@ -32,7 +32,7 @@ jobs: cache: gradle - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@8d49e559aae34d3e0eb16cde532684bc9702762b + uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 - name: Gradle cache uses: gradle/gradle-build-action@v2 diff --git a/.github/workflows/gradle-run-unit-tests.yml b/.github/workflows/gradle-run-unit-tests.yml index c036056aa34..780d53a7c9d 100644 --- a/.github/workflows/gradle-run-unit-tests.yml +++ b/.github/workflows/gradle-run-unit-tests.yml @@ -32,7 +32,7 @@ jobs: cache: gradle - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@8d49e559aae34d3e0eb16cde532684bc9702762b + uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 - name: Gradle cache uses: gradle/gradle-build-action@v2 diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/CompositeMessagesViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/CompositeMessageViewModel.kt similarity index 72% rename from app/src/main/kotlin/com/wire/android/ui/home/conversations/CompositeMessagesViewModel.kt rename to app/src/main/kotlin/com/wire/android/ui/home/conversations/CompositeMessageViewModel.kt index 66d25b8b82f..57055aedce3 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/CompositeMessagesViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/CompositeMessageViewModel.kt @@ -18,13 +18,15 @@ package com.wire.android.ui.home.conversations import androidx.annotation.VisibleForTesting -import androidx.compose.runtime.mutableStateMapOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.wire.android.navigation.EXTRA_CONVERSATION_ID -import com.wire.android.navigation.SavedStateViewModel +import com.wire.android.navigation.EXTRA_MESSAGE_ID import com.wire.kalium.logic.data.id.MessageButtonId -import com.wire.kalium.logic.data.id.MessageId import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.data.id.QualifiedIdMapper import com.wire.kalium.logic.feature.message.composite.SendButtonActionMessageUseCase @@ -33,28 +35,34 @@ import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class CompositeMessagesViewModel @Inject constructor( +class CompositeMessageViewModel @Inject constructor( private val sendButtonActionMessageUseCase: SendButtonActionMessageUseCase, qualifiedIdMapper: QualifiedIdMapper, savedStateHandle: SavedStateHandle, -) : SavedStateViewModel(savedStateHandle) { +) : ViewModel() { val conversationId: QualifiedID = qualifiedIdMapper.fromStringToQualifiedID( savedStateHandle.get(EXTRA_CONVERSATION_ID)!! ) - var pendingButtons = mutableStateMapOf() + private val messageId: String = savedStateHandle.get(EXTRA_MESSAGE_ID)!! + + var pendingButtonId: MessageButtonId? by mutableStateOf(null) @VisibleForTesting set - fun onButtonClicked(messageId: String, buttonId: String) { - if (pendingButtons.containsKey(messageId)) return + fun sendButtonActionMessage(buttonId: String) { + if (pendingButtonId != null) return - pendingButtons[messageId] = buttonId + pendingButtonId = buttonId viewModelScope.launch { sendButtonActionMessageUseCase(conversationId, messageId, buttonId) }.invokeOnCompletion { - pendingButtons.remove(messageId) + pendingButtonId = null } } + + companion object { + const val ARGS_KEY = "CompositeMessageViewModelKey" + } } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt index b7f7c3f6ea5..90b6874b0df 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationScreen.kt @@ -119,7 +119,6 @@ fun ConversationScreen( conversationCallViewModel: ConversationCallViewModel = hiltSavedStateViewModel(backNavArgs = backNavArgs), conversationMessagesViewModel: ConversationMessagesViewModel = hiltSavedStateViewModel(backNavArgs = backNavArgs), messageComposerViewModel: MessageComposerViewModel = hiltSavedStateViewModel(backNavArgs = backNavArgs), - compositeMessagesViewModel: CompositeMessagesViewModel = hiltSavedStateViewModel(backNavArgs = backNavArgs) ) { val coroutineScope = rememberCoroutineScope() val showDialog = remember { mutableStateOf(ConversationScreenDialogType.NONE) } @@ -220,7 +219,6 @@ fun ConversationScreen( onFailedMessageRetryClicked = messageComposerViewModel::retrySendingMessage, requestMentions = messageComposerViewModel::searchMembersToMention, onClearMentionSearchResult = messageComposerViewModel::clearMentionSearchResult, - compositeMessagesViewModel = compositeMessagesViewModel ) DeleteMessageDialog( state = messageComposerViewModel.deleteMessageDialogsState, @@ -307,7 +305,6 @@ private fun ConversationScreen( composerMessages: SharedFlow, conversationMessages: SharedFlow, conversationMessagesViewModel: ConversationMessagesViewModel, - compositeMessagesViewModel: CompositeMessagesViewModel, onSelfDeletingMessageRead: (UIMessage) -> Unit, onNewSelfDeletingMessagesStatus: (SelfDeletionTimer) -> Unit, tempWritableImageUri: Uri?, @@ -425,8 +422,6 @@ private fun ConversationScreen( tempWritableImageUri = tempWritableImageUri, tempWritableVideoUri = tempWritableVideoUri, snackBarHostState = conversationScreenState.snackBarHostState, - onMessageButtonClicked = compositeMessagesViewModel::onButtonClicked, - pendingButtonsMap = compositeMessagesViewModel.pendingButtons, ) } MenuModalSheetLayout( @@ -465,8 +460,6 @@ private fun ConversationScreenContent( onChangeSelfDeletionClicked: () -> Unit, onSearchMentionQueryChanged: (String) -> Unit, onClearMentionSearchResult: () -> Unit, - onMessageButtonClicked: (messageId: String, buttonId: String) -> Unit, - pendingButtonsMap: Map, tempWritableImageUri: Uri?, tempWritableVideoUri: Uri?, snackBarHostState: SnackbarHostState @@ -499,8 +492,6 @@ private fun ConversationScreenContent( conversationDetailsData = conversationDetailsData, onFailedMessageCancelClicked = onFailedMessageCancelClicked, onFailedMessageRetryClicked = onFailedMessageRetryClicked, - onMessageButtonClicked = onMessageButtonClicked, - pendingButtonsMap = pendingButtonsMap ) }, onChangeSelfDeletionClicked = onChangeSelfDeletionClicked, @@ -581,8 +572,6 @@ fun MessageList( conversationDetailsData: ConversationDetailsData, onFailedMessageRetryClicked: (String) -> Unit, onFailedMessageCancelClicked: (String) -> Unit, - onMessageButtonClicked: (messageId: String, buttonId: String) -> Unit, - pendingButtonsMap: Map ) { val mostRecentMessage = lazyPagingMessages.itemCount.takeIf { it > 0 }?.let { lazyPagingMessages[0] } @@ -639,8 +628,6 @@ fun MessageList( onSelfDeletingMessageRead = onSelfDeletingMessageRead, onFailedMessageCancelClicked = onFailedMessageCancelClicked, onFailedMessageRetryClicked = onFailedMessageRetryClicked, - onMessageButtonClicked = onMessageButtonClicked, - pendingButtonsMap = pendingButtonsMap ) } @@ -713,7 +700,6 @@ fun PreviewConversationScreen() { tempWritableVideoUri = null, onFailedMessageRetryClicked = {}, requestMentions = {}, - onClearMentionSearchResult = {}, - compositeMessagesViewModel = hiltViewModel() + onClearMentionSearchResult = {} ) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageItem.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageItem.kt index e0c80ef57f3..3ad6e8c3d1e 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageItem.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageItem.kt @@ -104,8 +104,6 @@ fun MessageItem( onSelfDeletingMessageRead: (UIMessage) -> Unit, onFailedMessageRetryClicked: (String) -> Unit = {}, onFailedMessageCancelClicked: (String) -> Unit = {}, - onMessageButtonClicked: (messageId: String, buttonId: String) -> Unit, - pendingButtonsMap: Map = emptyMap() ) { with(message) { val selfDeletionTimerState = rememberSelfDeletionTimer(header.messageStatus.expirationStatus) @@ -232,8 +230,6 @@ fun MessageItem( onImageClick = currentOnImageClick, onLongClick = onLongClick, onOpenProfile = onOpenProfile, - onMessageButtonClicked = onMessageButtonClicked, - pendingButtonsMap = pendingButtonsMap, ) } if (isMyMessage) { @@ -448,8 +444,6 @@ private fun MessageContent( audioMessagesState: Map, onAssetClick: Clickable, onImageClick: Clickable, - onMessageButtonClicked: (messageId: String, buttonId: String) -> Unit, - pendingButtonsMap: Map, onAudioClick: (String) -> Unit, onChangeAudioPosition: (String, Int) -> Unit, onLongClick: (() -> Unit)? = null, @@ -483,8 +477,6 @@ private fun MessageContent( onLongClick = onLongClick, onOpenProfile = onOpenProfile, buttonList = null, - onButtonClick = null, - pendingButton = null, messageId = message.header.messageId ) PartialDeliveryInformation(messageContent.deliveryStatus) @@ -507,9 +499,7 @@ private fun MessageContent( onLongClick = onLongClick, onOpenProfile = onOpenProfile, buttonList = messageContent.buttonList, - onButtonClick = onMessageButtonClicked, messageId = message.header.messageId, - pendingButton = pendingButtonsMap[message.header.messageId] ) } } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/EditMessageMenuItems.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/EditMessageMenuItems.kt index a0a3182946f..985691b4947 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/EditMessageMenuItems.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/EditMessageMenuItems.kt @@ -30,6 +30,7 @@ import com.wire.android.ui.common.bottomsheet.MenuItemIcon import com.wire.android.ui.home.conversations.model.ExpirationStatus import com.wire.android.ui.home.conversations.model.UIMessage import com.wire.android.ui.home.conversations.model.UIMessageContent +import com.wire.android.util.Copyable import com.wire.android.util.ui.UIText import com.wire.kalium.logic.data.message.mention.MessageMention @@ -49,39 +50,40 @@ fun EditMessageMenuItems( ): List<@Composable () -> Unit> { val localContext = LocalContext.current - val onCopyItemClick = remember(message) { - { - hideEditMessageMenu { - onCopyClick( - (message.messageContent as UIMessageContent.TextMessage).messageBody.message.asString( - localContext.resources - ) - ) + val isComposite = remember(message.header.messageId) { + message.messageContent is UIMessageContent.Composite + } + + val onCopyItemClick: (() -> Unit)? = remember(message.header.messageId) { + (message.messageContent as? Copyable)?.textToCopy(localContext.resources)?.let { + { + hideEditMessageMenu { onCopyClick(it) } } } } - val onDeleteItemClick = remember(message) { + + val onDeleteItemClick = remember(message.header.messageId) { { hideEditMessageMenu { onDeleteClick(message.header.messageId, message.isMyMessage) } } } - val onReactionItemClick = remember(message) { + val onReactionItemClick = remember(message.header.messageId) { { emoji: String -> hideEditMessageMenu { onReactionClick(message.header.messageId, emoji) } } } - val onReplyItemClick = remember(message) { + val onReplyItemClick = remember(message.header.messageId) { { hideEditMessageMenu { onReplyClick(message) } } } - val onDetailsItemClick = remember(message) { + val onDetailsItemClick = remember(message.header.messageId) { { hideEditMessageMenu { onDetailsClick(message.header.messageId, message.isMyMessage) @@ -132,6 +134,7 @@ fun EditMessageMenuItems( TextMessageEditMenuItems( isEphemeral = message.header.messageStatus.expirationStatus is ExpirationStatus.Expirable, isUploading = message.isPending, + isComposite = isComposite, onDeleteClick = onDeleteItemClick, onDetailsClick = onDetailsItemClick, onReactionClick = onReactionItemClick, diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/TextMessageMenuItems.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/TextMessageMenuItems.kt index 923d2f44402..03c4d7f26d7 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/TextMessageMenuItems.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/edit/TextMessageMenuItems.kt @@ -27,19 +27,20 @@ import com.wire.android.ui.edit.ReplyMessageOption fun TextMessageEditMenuItems( isEphemeral: Boolean, isUploading: Boolean, + isComposite: Boolean, onDeleteClick: () -> Unit, onDetailsClick: () -> Unit, onReplyClick: () -> Unit, - onCopyClick: () -> Unit, + onCopyClick: (() -> Unit)?, onReactionClick: (String) -> Unit, onEditClick: (() -> Unit)? = null ): List<@Composable () -> Unit> { return buildList { if (!isUploading) { - if (!isEphemeral) add { ReactionOption(onReactionClick) } + if (!isEphemeral && !isComposite) add { ReactionOption(onReactionClick) } add { MessageDetailsMenuOption(onDetailsClick) } - if (!isEphemeral) add { CopyItemMenuOption(onCopyClick) } - if (!isEphemeral) add { ReplyMessageOption(onReplyClick) } + onCopyClick?.also { add { CopyItemMenuOption(it) } } + if (!isEphemeral && !isComposite) add { ReplyMessageOption(onReplyClick) } if (!isEphemeral && onEditClick != null) add { EditMessageMenuOption(onEditClick) } } add { DeleteItemMenuOption(onDeleteClick) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt index 56190473ff4..66fe9621eba 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypes.kt @@ -20,7 +20,6 @@ package com.wire.android.ui.home.conversations.model -import android.annotation.SuppressLint import android.content.res.Resources import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -40,11 +39,15 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp +import androidx.core.os.bundleOf +import com.sebaslogen.resaca.hilt.hiltViewModelScoped import com.wire.android.model.Clickable import com.wire.android.model.ImageAsset +import com.wire.android.navigation.EXTRA_MESSAGE_ID import com.wire.android.ui.common.button.WireButtonState import com.wire.android.ui.common.button.WireSecondaryButton import com.wire.android.ui.common.dimensions +import com.wire.android.ui.home.conversations.CompositeMessageViewModel import com.wire.android.ui.home.conversations.model.messagetypes.asset.MessageAsset import com.wire.android.ui.home.conversations.model.messagetypes.image.DisplayableImageMessage import com.wire.android.ui.home.conversations.model.messagetypes.image.ImageMessageFailed @@ -80,9 +83,7 @@ internal fun MessageBody( isAvailable: Boolean, onLongClick: (() -> Unit)? = null, onOpenProfile: (String) -> Unit, - buttonList: List?, - pendingButton: String?, - onButtonClick: ((messageId: String, buttonId: String) -> Unit)? + buttonList: List? ) { val (displayMentions, text) = messageBody?.message?.let { mapToDisplayMentions(it, LocalContext.current.resources) @@ -110,8 +111,6 @@ internal fun MessageBody( MessageButtonsContent( messageId = messageId, buttonList = it, - onClick = onButtonClick, - pendingButton = pendingButton ) } } @@ -119,22 +118,39 @@ internal fun MessageBody( @Composable fun MessageButtonsContent( messageId: String, - pendingButton: String?, buttonList: List, - onClick: ((messageId: String, buttonId: String) -> Unit)? ) { + val viewModel = hiltViewModelScoped( + key = "${CompositeMessageViewModel.ARGS_KEY}$messageId", + defaultArguments = bundleOf( + EXTRA_MESSAGE_ID to messageId, + ) + ) Column( modifier = Modifier .wrapContentSize() ) { - for (index in buttonList.indices) { val button = buttonList[index] - MessageButtonItem( - messageId = messageId, - pendingButtonId = pendingButton, - button = button, - onClick = onClick + val onCLick = remember(button.isSelected) { + if (!button.isSelected) { + { viewModel.sendButtonActionMessage(button.id) } + } else { + { } + } + } + + val isPending = viewModel.pendingButtonId == button.id + + val state = if (button.isSelected) WireButtonState.Selected + else if (viewModel.pendingButtonId != null) WireButtonState.Disabled + else WireButtonState.Default + + WireSecondaryButton( + loading = isPending, + text = button.text, + onClick = onCLick, + state = state ) if (index != buttonList.lastIndex) { Spacer(modifier = Modifier.padding(top = dimensions().spacing8x)) @@ -143,40 +159,6 @@ fun MessageButtonsContent( } } -@SuppressLint("RememberReturnType") -@Composable -fun MessageButtonItem( - messageId: String, - button: MessageButton, - pendingButtonId: MessageButtonId?, - onClick: ((messageId: String, buttonId: String) -> Unit)? -) { - val onCLick = remember(button.isSelected) { - onClick?.let { - if (!button.isSelected) { - { onClick(messageId, button.id) } - } else { - { } - } - } ?: { } - } - - val isPending = remember(pendingButtonId) { - pendingButtonId == button.id - } - - val state = if (button.isSelected) WireButtonState.Selected - else if (pendingButtonId != null) WireButtonState.Disabled - else WireButtonState.Default - - WireSecondaryButton( - loading = isPending, - text = button.text, - onClick = onCLick, - state = state - ) -} - @OptIn(ExperimentalFoundationApi::class) @Composable fun MessageImage( diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesPreview.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesPreview.kt index 7b29bdfa112..1adc4cc8f4c 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesPreview.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/MessageTypesPreview.kt @@ -66,8 +66,7 @@ fun PreviewMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = {}, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -96,8 +95,7 @@ fun PreviewMessageWithReactions() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = {}, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -137,8 +135,7 @@ fun PreviewMessageWithReply() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = {}, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -168,8 +165,7 @@ fun PreviewDeletedMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -200,8 +196,7 @@ fun PreviewFailedSendMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -232,8 +227,7 @@ fun PreviewFailedDecryptionMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -254,8 +248,7 @@ fun PreviewAssetMessageWithReactions() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -344,8 +337,7 @@ fun PreviewImageMessageUploaded() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -366,8 +358,7 @@ fun PreviewImageMessageUploading() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -394,8 +385,7 @@ fun PreviewImageMessageFailedUpload() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -417,8 +407,7 @@ fun PreviewMessageWithSystemMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = { }, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) SystemMessageItem( mockMessageWithKnock.copy( @@ -462,8 +451,7 @@ fun PreviewMessagesWithUnavailableQuotedMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = {}, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } @@ -485,8 +473,7 @@ fun PreviewAggregatedMessagesWithErrorMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = {}, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) MessageItem( message = mockMessageWithText.copy( @@ -508,8 +495,7 @@ fun PreviewAggregatedMessagesWithErrorMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = {}, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) MessageItem( message = mockMessageWithText.copy( @@ -531,8 +517,7 @@ fun PreviewAggregatedMessagesWithErrorMessage() { onReactionClicked = { _, _ -> }, onResetSessionClicked = { _, _ -> }, onSelfDeletingMessageRead = {}, - conversationDetailsData = ConversationDetailsData.None, - onMessageButtonClicked = { _, _ -> } + conversationDetailsData = ConversationDetailsData.None ) } } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt index ae55791da76..cd722eb4eae 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/model/UIMessage.kt @@ -20,6 +20,7 @@ package com.wire.android.ui.home.conversations.model +import android.content.res.Resources import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.runtime.Stable @@ -28,6 +29,7 @@ import com.wire.android.model.ImageAsset import com.wire.android.model.UserAvatarData import com.wire.android.ui.home.conversationslist.model.Membership import com.wire.android.ui.home.messagecomposer.SelfDeletionDuration +import com.wire.android.util.Copyable import com.wire.android.util.ui.UIText import com.wire.android.util.uiMessageDateTime import com.wire.kalium.logic.data.conversation.ClientId @@ -211,12 +213,16 @@ sealed class UIMessageContent { data class TextMessage( val messageBody: MessageBody, override val deliveryStatus: DeliveryStatusContent = DeliveryStatusContent.CompleteDelivery - ) : Regular(), PartialDeliverable + ) : Regular(), PartialDeliverable, Copyable { + override fun textToCopy(resources: Resources): String = messageBody.message.asString(resources) + } data class Composite( val messageBody: MessageBody?, val buttonList: List - ) : Regular() + ) : Regular(), Copyable { + override fun textToCopy(resources: Resources): String? = messageBody?.message?.asString(resources) + } object Deleted : Regular() diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModel.kt index dd967acc227..b7f9769f3b0 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/NewConversationViewModel.kt @@ -226,6 +226,10 @@ class NewConversationViewModel @Inject constructor( appLogger.w("Error while creating a group ${result.cause}") groupOptionsState = groupOptionsState.copy(isLoading = false, error = GroupOptionState.Error.Unknown) } + + is CreateGroupConversationUseCase.Result.BackendConflictFailure -> { + // TODO: handle this case + } } } diff --git a/app/src/main/kotlin/com/wire/android/util/Copyable.kt b/app/src/main/kotlin/com/wire/android/util/Copyable.kt new file mode 100644 index 00000000000..86c6ad03b4d --- /dev/null +++ b/app/src/main/kotlin/com/wire/android/util/Copyable.kt @@ -0,0 +1,29 @@ +/* + * 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.util + +import android.content.res.Resources + +/** + * Interface for classes that can be copied to the clipboard. + * @see [TextMessageEditMenuItems] + * if a UIMessage implement this interface the copy option will be displayed in the edit menu. + */ +interface Copyable { + fun textToCopy(resources: Resources): String? +} diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/CompositeMessagesViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/CompositeMessageViewModelTest.kt similarity index 85% rename from app/src/test/kotlin/com/wire/android/ui/home/conversations/CompositeMessagesViewModelTest.kt rename to app/src/test/kotlin/com/wire/android/ui/home/conversations/CompositeMessageViewModelTest.kt index e8c26aec8a1..4eb26fa1a20 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/CompositeMessagesViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/CompositeMessageViewModelTest.kt @@ -29,23 +29,22 @@ import io.mockk.every import io.mockk.impl.annotations.MockK import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(CoroutineTestExtension::class) -class CompositeMessagesViewModelTest { +class CompositeMessageViewModelTest { @Test fun `given pending button, when button is clicked, then do Nothing`() = runTest { // Arrange val (arrangement, viewModel) = Arrangement().arrange() - val messageId = "messageId" val buttonId = "buttonId" - viewModel.pendingButtons[messageId] = buttonId + viewModel.pendingButtonId = buttonId // Act - viewModel.onButtonClicked(messageId, buttonId) + viewModel.sendButtonActionMessage(buttonId) advanceUntilIdle() // Assert @@ -60,13 +59,13 @@ class CompositeMessagesViewModelTest { val (arrangement, viewModel) = Arrangement() .withButtonActionMessage(SendButtonActionMessageUseCase.Result.Success) .arrange() - val messageId = "messageId" + val buttonId = "buttonId" // Act - viewModel.onButtonClicked(messageId, buttonId) + viewModel.sendButtonActionMessage(buttonId) advanceUntilIdle() - assertFalse(viewModel.pendingButtons.containsKey(messageId)) + assertNull(viewModel.pendingButtonId) // Assert coVerify(exactly = 1) { @@ -76,6 +75,7 @@ class CompositeMessagesViewModelTest { private companion object { const val CONVERSION_ID_STRING = "some-dummy-value@some.dummy.domain" + const val MESSAGE_ID = "message-id" } private class Arrangement { @@ -90,9 +90,10 @@ class CompositeMessagesViewModelTest { init { MockKAnnotations.init(this) every { savedStateHandle.get(any()) } returns CONVERSION_ID_STRING + every { savedStateHandle.get(any()) } returns MESSAGE_ID } - private val viewModel = CompositeMessagesViewModel(sendButtonActionMessage, qualifiedIdMapper, savedStateHandle) + private val viewModel = CompositeMessageViewModel(sendButtonActionMessage, qualifiedIdMapper, savedStateHandle) fun withButtonActionMessage( result: SendButtonActionMessageUseCase.Result diff --git a/git b/git deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e085f6119b3..4328c9a636c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ androidx-paging3 = "3.1.1" androidx-paging3Compose = "1.0.0-alpha18" androidx-splashscreen = "1.0.1" androidx-workManager = "2.8.1" -androidx-browser = "1.3.0" +androidx-browser = "1.5.0" # Compose compose = "1.5.0-beta03" diff --git a/kalium b/kalium index edb6f31270f..8532357e2f8 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit edb6f31270f83cc707ec0bf484e9fd5eac41248b +Subproject commit 8532357e2f898867e0292e2335be66d32aa9f83c