From 95baa5a479ea37e79f9d9a04e967cc8159609b78 Mon Sep 17 00:00:00 2001 From: Alexandre Ferris Date: Fri, 21 Jul 2023 10:06:19 +0200 Subject: [PATCH 01/12] fix: change audio extension from .mp3 to .m4a (#1986) --- .../ui/home/messagecomposer/recordaudio/AudioMediaRecorder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/AudioMediaRecorder.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/AudioMediaRecorder.kt index 8a37b3f805a..38d671c6c1e 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/AudioMediaRecorder.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/AudioMediaRecorder.kt @@ -125,7 +125,7 @@ class AudioMediaRecorder @Inject constructor( private companion object { fun getRecordingAudioFileName(): String = - "wire-audio-${DateTimeUtil.currentInstant().audioFileDateTime()}.mp3" + "wire-audio-${DateTimeUtil.currentInstant().audioFileDateTime()}.m4a" const val SIZE_OF_1MB = 1024 * 1024 } } From f803169bad49f3b57f45a5df1b9d6e3b49b88292 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jul 2023 08:17:39 +0000 Subject: [PATCH 02/12] chore(deps): bump hilt from 2.38.1 to 2.47 (#1985) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Vitor Hugo Schwaab --- buildSrc/build.gradle.kts | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index e54159bc2e1..1a08e63a0ff 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,7 +23,7 @@ private object Dependencies { const val detektGradlePlugin = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.19.0" const val junit = "junit:junit:4.13" const val kluent = "org.amshove.kluent:kluent:1.73" - const val hilt = "com.google.dagger:hilt-android-gradle-plugin:2.38.1" + const val hilt = "com.google.dagger:hilt-android-gradle-plugin:2.47" const val spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.1.2" const val junit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.9.3.0" const val grgit = "org.ajoberstar.grgit:grgit-core:5.2.0" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fb9a8da2e95..2087b0070c6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,7 +44,7 @@ compose-material3 = "1.1.0" compose-navigation = "2.6.0" # Hilt -hilt = "2.45" +hilt = "2.47" hilt-composeNavigation = "1.0.0" hilt-work = "1.0.0" From edb75c9325bdd70846098799a4a7a6458690b67b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:00:32 +0200 Subject: [PATCH 03/12] chore(deps): bump mockk from 1.13.4 to 1.13.5 (#1987) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2087b0070c6..f8a2334e086 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -73,7 +73,7 @@ androidx-text-archCore = "2.1.0" junit4 = "4.13" junit5 = "5.8.2" kluent = "1.73" -mockk = "1.13.4" +mockk = "1.13.5" okio = "3.2.0" turbine = "1.0.0" From 60427b4c430bbf06abeee9b2d0b4955d30c90108 Mon Sep 17 00:00:00 2001 From: Mohamad Jaara Date: Fri, 21 Jul 2023 09:01:44 +0000 Subject: [PATCH 04/12] fix: client to UI model mapping (#1988) --- .../android/ui/authentication/devices/model/Device.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt index 347d1d350aa..19cdabbfd21 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/model/Device.kt @@ -41,11 +41,12 @@ data class Device( val isVerified: Boolean = false ) { constructor(client: Client) : this( - client.displayName(), - client.id, - client.registrationTime?.toIsoDateTimeString(), - client.lastActiveInWholeWeeks(), - client.isVerified + name = client.displayName(), + clientId = client.id, + registrationTime = client.registrationTime?.toIsoDateTimeString(), + lastActiveInWholeWeeks = client.lastActiveInWholeWeeks(), + isValid = client.isVerified, + isVerified = client.isVerified ) } From f5267d558d778029077cf1f9ee792cb420b01f9d Mon Sep 17 00:00:00 2001 From: Mateusz Date: Fri, 21 Jul 2023 12:54:51 +0200 Subject: [PATCH 05/12] fix: missing self deleting text label and enabled button state[WPB-3312] (#1978) Co-authored-by: Tommaso Piazza <196761+tmspzz@users.noreply.github.com> --- .../ui/home/messagecomposer/AdditionalOptions.kt | 6 +++++- .../ui/home/messagecomposer/MessageComposeActions.kt | 7 ++++--- .../ui/home/messagecomposer/MessageComposer.kt | 4 +++- .../ui/home/messagecomposer/MessageComposerInput.kt | 9 ++++++--- .../state/MessageComposerStateHolder.kt | 2 +- .../state/MessageCompositionHolder.kt | 1 - .../state/MessageCompositionInputStateHolder.kt | 12 ++++++++++++ 7 files changed, 31 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/AdditionalOptions.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/AdditionalOptions.kt index b7a7d04eb17..4aa9e9e425f 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/AdditionalOptions.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/AdditionalOptions.kt @@ -62,6 +62,7 @@ fun AdditionalOptionsMenu( selectedOption: AdditionalOptionSelectItem, isFileSharingEnabled: Boolean, isSelfDeletingSettingEnabled: Boolean, + isSelfDeletingActive: Boolean, isEditing: Boolean, isMentionActive: Boolean, onOnSelfDeletingOptionClicked: (() -> Unit)? = null, @@ -82,8 +83,9 @@ fun AdditionalOptionsMenu( isFileSharingEnabled = isFileSharingEnabled, isEditing = isEditing, isSelfDeletingSettingEnabled = isSelfDeletingSettingEnabled, + isSelfDeletingActive = isSelfDeletingActive, isMentionActive = isMentionActive, - onMentionButtonClicked = onMentionButtonClicked ?: {}, + onMentionButtonClicked = onMentionButtonClicked, onAdditionalOptionsMenuClicked = onAdditionalOptionsMenuClicked, onGifButtonClicked = onGifOptionClicked ?: {}, onSelfDeletionOptionButtonClicked = onOnSelfDeletingOptionClicked ?: {}, @@ -156,6 +158,7 @@ fun AttachmentAndAdditionalOptionsMenuItems( onPingClicked: () -> Unit = {}, onSelfDeletionOptionButtonClicked: () -> Unit, isSelfDeletingSettingEnabled: Boolean, + isSelfDeletingActive: Boolean, onGifButtonClicked: () -> Unit = {}, onRichEditingButtonClicked: () -> Unit = {}, modifier: Modifier = Modifier @@ -172,6 +175,7 @@ fun AttachmentAndAdditionalOptionsMenuItems( onPingButtonClicked = onPingClicked, onSelfDeletionOptionButtonClicked = onSelfDeletionOptionButtonClicked, isSelfDeletingSettingEnabled = isSelfDeletingSettingEnabled, + isSelfDeletingActive = isSelfDeletingActive, onGifButtonClicked = onGifButtonClicked, onRichEditingButtonClicked = onRichEditingButtonClicked ) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposeActions.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposeActions.kt index a6e2e364bef..0572aa910f6 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposeActions.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposeActions.kt @@ -47,6 +47,7 @@ fun MessageComposeActions( isFileSharingEnabled: Boolean = true, isMentionActive: Boolean = true, isSelfDeletingSettingEnabled: Boolean = true, + isSelfDeletingActive: Boolean = false, onMentionButtonClicked: () -> Unit, onAdditionalOptionButtonClicked: () -> Unit, onPingButtonClicked: () -> Unit, @@ -70,6 +71,7 @@ fun MessageComposeActions( onRichEditingButtonClicked, onGifButtonClicked, isSelfDeletingSettingEnabled, + isSelfDeletingActive, onSelfDeletionOptionButtonClicked, onPingButtonClicked, onMentionButtonClicked @@ -86,6 +88,7 @@ private fun ComposingActions( onRichEditingButtonClicked: () -> Unit, onGifButtonClicked: () -> Unit, isSelfDeletingSettingEnabled: Boolean, + isSelfDeletingActive: Boolean, onSelfDeletionOptionButtonClicked: () -> Unit, onPingButtonClicked: () -> Unit, onMentionButtonClicked: () -> Unit @@ -112,7 +115,7 @@ private fun ComposingActions( if (EmojiIcon) AddEmojiAction({}) if (GifIcon) AddGifAction(onGifButtonClicked) if (isSelfDeletingSettingEnabled) SelfDeletingMessageAction( - isSelected = false, + isSelected = isSelfDeletingActive, onButtonClicked = onSelfDeletionOptionButtonClicked ) if (PingIcon) PingAction(onPingButtonClicked) @@ -131,8 +134,6 @@ fun EditingActions( onRichEditingButtonClicked: () -> Unit, onMentionButtonClicked: () -> Unit ) { - val localFeatureVisibilityFlags = LocalFeatureVisibilityFlags.current - Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceEvenly, diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposer.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposer.kt index faeec4eb8fe..02ca4601caf 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposer.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposer.kt @@ -79,6 +79,7 @@ import com.wire.android.util.ui.KeyboardHeight import com.wire.kalium.logic.feature.conversation.InteractionAvailability import com.wire.kalium.logic.feature.conversation.SecurityClassificationType import com.wire.kalium.logic.feature.selfDeletingMessages.SelfDeletionTimer +import com.wire.kalium.logic.util.isPositiveNotNull import kotlin.time.Duration @Composable @@ -350,7 +351,7 @@ private fun ActiveMessageComposer( messageComposition = messageComposition.value, inputSize = messageCompositionInputStateHolder.inputSize, inputType = messageCompositionInputStateHolder.inputType, - inputVisiblity = messageCompositionInputStateHolder.inputVisibility, + inputVisibility = messageCompositionInputStateHolder.inputVisibility, inputFocused = messageCompositionInputStateHolder.inputFocused, onInputFocusedChanged = ::onInputFocusedChanged, onToggleInputSize = messageCompositionInputStateHolder::toggleInputSize, @@ -399,6 +400,7 @@ private fun ActiveMessageComposer( isEditing = messageCompositionInputStateHolder.inputType is MessageCompositionType.Editing, isFileSharingEnabled = messageComposerViewState.value.isFileSharingEnabled, isSelfDeletingSettingEnabled = isSelfDeletingSettingEnabled, + isSelfDeletingActive = messageComposerViewState.value.selfDeletionTimer.duration.isPositiveNotNull(), isMentionActive = messageComposerViewState.value.mentionSearchResult.isNotEmpty(), onMentionButtonClicked = { messageCompositionHolder.startMention( diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposerInput.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposerInput.kt index f7ccabd7015..bc47eacfdc2 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposerInput.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageComposerInput.kt @@ -87,6 +87,7 @@ fun InactiveMessageComposerInput( focusColor = Color.Transparent, placeholderColor = colorsScheme().secondaryText ), + placeHolderText = stringResource(id = R.string.label_type_a_message), messageText = messageText, onMessageTextChanged = { // non functional @@ -105,7 +106,7 @@ fun ActiveMessageComposerInput( messageComposition: MessageComposition, inputSize: MessageCompositionInputSize, inputType: MessageCompositionType, - inputVisiblity: Boolean, + inputVisibility: Boolean, inputFocused: Boolean, onMessageTextChanged: (TextFieldValue) -> Unit, onSendButtonClicked: () -> Unit, @@ -119,7 +120,7 @@ fun ActiveMessageComposerInput( onLineBottomYCoordinateChanged: (Float) -> Unit, modifier: Modifier = Modifier ) { - if (inputVisiblity) { + if (inputVisibility) { Column( modifier = modifier .wrapContentSize() @@ -158,6 +159,7 @@ fun ActiveMessageComposerInput( inputFocused = inputFocused, colors = inputType.inputTextColor(), messageText = messageComposition.messageTextFieldValue, + placeHolderText = inputType.labelText(), onMessageTextChanged = onMessageTextChanged, singleLine = false, onFocusChanged = onInputFocusedChanged, @@ -209,6 +211,7 @@ private fun MessageComposerTextInput( colors: WireTextFieldColors, singleLine: Boolean, messageText: TextFieldValue, + placeHolderText: String, onMessageTextChanged: (TextFieldValue) -> Unit, onFocusChanged: (Boolean) -> Unit = {}, onSelectedLineIndexChanged: (Int) -> Unit = { }, @@ -233,7 +236,7 @@ private fun MessageComposerTextInput( maxLines = Int.MAX_VALUE, textStyle = MaterialTheme.wireTypography.body01, // Add an extra space so that the cursor is placed one space before "Type a message" - placeholderText = " " + stringResource(R.string.label_type_a_message), + placeholderText = " $placeHolderText", modifier = modifier.then( Modifier .onFocusChanged { focusState -> diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageComposerStateHolder.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageComposerStateHolder.kt index d60e8659aee..36cba9b6e7f 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageComposerStateHolder.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageComposerStateHolder.kt @@ -54,6 +54,7 @@ fun rememberMessageComposerStateHolder( messageComposerViewState.value.selfDeletionTimer } } + val messageCompositionInputStateHolder = rememberSaveable( saver = MessageCompositionInputStateHolder.saver( messageComposition = messageCompositionHolder.messageComposition, @@ -95,7 +96,6 @@ class MessageComposerStateHolder( val modalBottomSheetState: WireModalSheetState ) { val messageComposition = messageCompositionHolder.messageComposition - val isTransitionToKeyboardOnGoing @Composable get() = additionalOptionStateHolder.additionalOptionsSubMenuState == AdditionalOptionSubMenuState.Hidden && !KeyboardHelper.isKeyboardVisible() && diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionHolder.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionHolder.kt index c30b92dd264..0ea5e82cf5a 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionHolder.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionHolder.kt @@ -50,7 +50,6 @@ class MessageCompositionHolder( } val messageComposition: MutableState = mutableStateOf(MessageComposition.DEFAULT) - fun setReply(message: UIMessage.Regular) { val senderId = message.header.userId ?: return diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionInputStateHolder.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionInputStateHolder.kt index d63f97129ba..e0e6e41341a 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionInputStateHolder.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/state/MessageCompositionInputStateHolder.kt @@ -26,6 +26,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.Saver import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import com.wire.android.R import com.wire.android.ui.common.colorsScheme import com.wire.android.ui.common.textfield.WireTextFieldColors import com.wire.android.ui.common.textfield.wireTextFieldColors @@ -159,6 +161,9 @@ sealed class MessageCompositionType { @Composable open fun backgroundColor(): Color = colorsScheme().messageComposerBackgroundColor + @Composable + open fun labelText(): String = stringResource(R.string.label_type_a_message) + class Composing(messageCompositionState: MutableState, val messageType: State) : MessageCompositionType() { @@ -177,6 +182,13 @@ sealed class MessageCompositionType { } else { super.inputTextColor() } + + @Composable + override fun labelText(): String = if (messageType.value is MessageType.SelfDeleting) { + stringResource(id = R.string.self_deleting_message_label) + } else { + super.labelText() + } } class Editing( From 4019346f2d5b292c67c3771846ce301951f6cfa4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jul 2023 14:17:33 +0200 Subject: [PATCH 06/12] chore(deps): bump androidx.test:core from 1.4.0 to 1.5.0 (#1991) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f8a2334e086..96ef7241886 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,7 +63,7 @@ leakCanary = "2.7" # Testing androidx-espresso = "3.4.0" -androidx-test-core = "1.4.0" +androidx-test-core = "1.5.0" androidx-test-extensions = "1.1.1" androidx-test-orchestrator = "1.4.1" androidx-test-rules = "1.4.0" From 74bb365f736eee04c1ba138c07c023ac8ea58e2a Mon Sep 17 00:00:00 2001 From: boris Date: Fri, 21 Jul 2023 18:51:45 +0300 Subject: [PATCH 07/12] feat: Indicate MLS validated conversations (#1913) Co-authored-by: Mojtaba Chenani --- .../com/wire/android/di/CoreLogicModule.kt | 5 + .../conversations/ConversationTopAppBar.kt | 18 ++++ .../info/ConversationInfoViewModel.kt | 13 ++- .../info/ConversationInfoViewState.kt | 2 + .../res/drawable/ic_certificate_valid_mls.xml | 27 +++++ .../drawable/ic_certificate_valid_proteus.xml | 31 ++++++ app/src/main/res/values/strings.xml | 2 + .../ConversationInfoViewModelArrangement.kt | 18 +++- .../info/ConversationInfoViewModelTest.kt | 99 ++++++++++++++++++- 9 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/drawable/ic_certificate_valid_mls.xml create mode 100644 app/src/main/res/drawable/ic_certificate_valid_proteus.xml 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 8f8e9d1bbf1..0a91750ca5e 100644 --- a/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt +++ b/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt @@ -1221,4 +1221,9 @@ class UseCaseModule { @KaliumCoreLogic coreLogic: CoreLogic, @CurrentAccount currentAccount: UserId ): ObserveScreenshotCensoringConfigUseCase = coreLogic.getSessionScope(currentAccount).observeScreenshotCensoringConfig + + @ViewModelScoped + @Provides + fun provideGetConversationVerificationStatusUseCase(@KaliumCoreLogic coreLogic: CoreLogic, @CurrentAccount currentAccount: UserId) = + coreLogic.getSessionScope(currentAccount).getConversationVerificationStatus } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationTopAppBar.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationTopAppBar.kt index 40d3f9549f7..41a9c9df374 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationTopAppBar.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/ConversationTopAppBar.kt @@ -20,11 +20,13 @@ package com.wire.android.ui.home.conversations +import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape @@ -62,8 +64,10 @@ import com.wire.android.ui.theme.wireDimensions import com.wire.android.ui.theme.wireTypography import com.wire.android.util.debug.LocalFeatureVisibilityFlags import com.wire.android.util.ui.UIText +import com.wire.kalium.logic.data.conversation.ConversationVerificationStatus import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.data.user.UserAvailabilityStatus +import com.wire.kalium.logic.feature.conversation.ConversationProtocol @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -97,6 +101,20 @@ fun ConversationScreenTopAppBar( overflow = TextOverflow.Ellipsis, modifier = Modifier.weight(weight = 1f, fill = false) ) + if (conversationInfoViewState.verificationStatus?.status == ConversationVerificationStatus.VERIFIED) { + val (iconId, contentDescriptionId) = when (conversationInfoViewState.verificationStatus.protocol) { + ConversationProtocol.MLS -> + R.drawable.ic_certificate_valid_mls to R.string.content_description_mls_certificate_valid + + ConversationProtocol.PROTEUS -> + R.drawable.ic_certificate_valid_proteus to R.string.content_description_proteus_certificate_valid + } + Image( + modifier = Modifier.padding(start = dimensions().spacing4x), + painter = painterResource(id = iconId), + contentDescription = stringResource(contentDescriptionId) + ) + } if (isDropDownEnabled && isInteractionEnabled) { Icon( painter = painterResource(id = R.drawable.ic_dropdown_icon), 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 fca36a2e336..9f532dfcffd 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 @@ -46,6 +46,8 @@ import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.data.id.QualifiedIdMapper import com.wire.kalium.logic.data.user.ConnectionState import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.logic.feature.conversation.ConversationVerificationStatusResult +import com.wire.kalium.logic.feature.conversation.GetConversationVerificationStatusUseCase import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseCase import com.wire.kalium.logic.feature.user.GetSelfUserUseCase import dagger.hilt.android.lifecycle.HiltViewModel @@ -62,7 +64,8 @@ class ConversationInfoViewModel @Inject constructor( private val observeConversationDetails: ObserveConversationDetailsUseCase, private val observerSelfUser: GetSelfUserUseCase, private val wireSessionImageLoader: WireSessionImageLoader, - private val dispatchers: DispatcherProvider + private val dispatchers: DispatcherProvider, + private val getConversationVerificationStatus: GetConversationVerificationStatusUseCase ) : SavedStateViewModel(savedStateHandle) { var conversationInfoViewState by mutableStateOf(ConversationInfoViewState()) @@ -81,6 +84,12 @@ class ConversationInfoViewModel @Inject constructor( viewModelScope.launch { selfUserId = observerSelfUser().first().id } + viewModelScope.launch { + val result = getConversationVerificationStatus(conversationId) + if (result is ConversationVerificationStatusResult.Success) { + conversationInfoViewState = conversationInfoViewState.copy(verificationStatus = result) + } + } } /* @@ -118,6 +127,7 @@ class ConversationInfoViewModel @Inject constructor( navigateToHome() } } + is StorageFailure.Generic -> appLogger.e("An error occurred when fetching details of the conversation", failure.rootCause) } } @@ -126,6 +136,7 @@ class ConversationInfoViewModel @Inject constructor( val (isConversationUnavailable, _) = when (conversationDetails) { is ConversationDetails.OneOne -> conversationDetails.otherUser .run { isUnavailableUser to (connectionStatus == ConnectionState.BLOCKED) } + else -> false to false } 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 6a4146dc59a..a69f4f82d09 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 @@ -27,6 +27,7 @@ import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.data.user.ConnectionState import com.wire.kalium.logic.data.user.UserAvailabilityStatus import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.logic.feature.conversation.ConversationVerificationStatusResult data class ConversationInfoViewState( val conversationName: UIText = UIText.DynamicString(""), @@ -34,6 +35,7 @@ data class ConversationInfoViewState( val conversationAvatar: ConversationAvatar = ConversationAvatar.None, val hasUserPermissionToEdit: Boolean = false, val conversationType: Conversation.Type = Conversation.Type.ONE_ON_ONE, + val verificationStatus: ConversationVerificationStatusResult.Success? = null, ) sealed class ConversationDetailsData { diff --git a/app/src/main/res/drawable/ic_certificate_valid_mls.xml b/app/src/main/res/drawable/ic_certificate_valid_mls.xml new file mode 100644 index 00000000000..9d575b4d809 --- /dev/null +++ b/app/src/main/res/drawable/ic_certificate_valid_mls.xml @@ -0,0 +1,27 @@ + + + + diff --git a/app/src/main/res/drawable/ic_certificate_valid_proteus.xml b/app/src/main/res/drawable/ic_certificate_valid_proteus.xml new file mode 100644 index 00000000000..d6c47882bbe --- /dev/null +++ b/app/src/main/res/drawable/ic_certificate_valid_proteus.xml @@ -0,0 +1,31 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 921b86ca08f..032981e0e4c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -167,6 +167,8 @@ Record Audio Stop Recording Audio Send Audio Message + All devices of all participants have a valid MLS certificate + All of all participants are verified (Proteus) https://support.wire.com/hc/en-us/articles/207948115-Why-was-I-notified-that-a-message-from-a-contact-was-not-received- 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 5d5145b92c8..539849b038a 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 @@ -27,9 +27,13 @@ import com.wire.android.framework.TestUser import com.wire.android.navigation.NavigationManager import com.wire.android.util.ui.WireSessionImageLoader import com.wire.kalium.logic.data.conversation.ConversationDetails +import com.wire.kalium.logic.data.conversation.ConversationVerificationStatus import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.data.id.QualifiedIdMapper +import com.wire.kalium.logic.feature.conversation.ConversationProtocol +import com.wire.kalium.logic.feature.conversation.ConversationVerificationStatusResult +import com.wire.kalium.logic.feature.conversation.GetConversationVerificationStatusUseCase import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseCase import com.wire.kalium.logic.feature.user.GetSelfUserUseCase import io.mockk.MockKAnnotations @@ -65,6 +69,9 @@ class ConversationInfoViewModelArrangement { @MockK private lateinit var wireSessionImageLoader: WireSessionImageLoader + @MockK + private lateinit var getConversationVerificationStatus: GetConversationVerificationStatusUseCase + private val viewModel: ConversationInfoViewModel by lazy { ConversationInfoViewModel( qualifiedIdMapper, @@ -73,7 +80,8 @@ class ConversationInfoViewModelArrangement { observeConversationDetails, observerSelfUser, wireSessionImageLoader, - TestDispatcherProvider() + TestDispatcherProvider(), + getConversationVerificationStatus ) } @@ -87,6 +95,10 @@ class ConversationInfoViewModelArrangement { coEvery { observeConversationDetails(any()) } returns conversationDetailsChannel.consumeAsFlow().map { ObserveConversationDetailsUseCase.Result.Success(it) } + coEvery { getConversationVerificationStatus(any()) } returns ConversationVerificationStatusResult.Success( + ConversationProtocol.PROTEUS, + ConversationVerificationStatus.NOT_VERIFIED + ) } suspend fun withConversationDetailUpdate(conversationDetails: ConversationDetails) = apply { @@ -100,5 +112,9 @@ class ConversationInfoViewModelArrangement { coEvery { observerSelfUser() } returns flowOf(TestUser.SELF_USER) } + suspend fun withVerificationStatus(result: ConversationVerificationStatusResult) = apply { + coEvery { getConversationVerificationStatus(any()) } returns result + } + fun arrange() = this to viewModel } diff --git a/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelTest.kt index 9ca5d9aad19..c46a9df27f0 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/conversations/info/ConversationInfoViewModelTest.kt @@ -28,10 +28,14 @@ import com.wire.android.ui.home.conversations.mockConversationDetailsGroup import com.wire.android.ui.home.conversations.withMockConversationDetailsOneOnOne import com.wire.android.util.EMPTY import com.wire.android.util.ui.UIText +import com.wire.kalium.logic.StorageFailure import com.wire.kalium.logic.data.conversation.ConversationDetails +import com.wire.kalium.logic.data.conversation.ConversationVerificationStatus import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.logic.feature.conversation.ConversationProtocol +import com.wire.kalium.logic.feature.conversation.ConversationVerificationStatusResult import io.mockk.coEvery import io.mockk.coVerify import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -123,7 +127,7 @@ class ConversationInfoViewModelTest { NavigationCommand(NavigationItem.OtherUserProfile.getRouteWithArgs(listOf(userId, arrangement.conversationId))) ) } - cancel() + cancel() } } @@ -269,4 +273,97 @@ class ConversationInfoViewModelTest { cancel() } } + + @Test + fun `given a not-verified MLS conversation, then mlsVerificationStatus is not verified`() = runTest { + // Given + val result = ConversationVerificationStatusResult.Success( + ConversationProtocol.MLS, + ConversationVerificationStatus.NOT_VERIFIED + ) + val (_, viewModel) = ConversationInfoViewModelArrangement() + .withVerificationStatus(result) + .withSelfUser() + .arrange() + + // then + assertEquals( + result, + viewModel.conversationInfoViewState.verificationStatus + ) + } + + @Test + fun `given conversation is MLS verified, then mlsVerificationStatus is verified`() = runTest { + // Given + val result = ConversationVerificationStatusResult.Success( + ConversationProtocol.MLS, + ConversationVerificationStatus.VERIFIED + ) + val (_, viewModel) = ConversationInfoViewModelArrangement() + .withVerificationStatus(result) + .withSelfUser() + .arrange() + + // then + assertEquals( + result, + viewModel.conversationInfoViewState.verificationStatus + ) + } + + @Test + fun `given a verified Proteus conversation, then proteusVerificationStatus is verified`() = runTest { + // Given + val result = ConversationVerificationStatusResult.Success( + ConversationProtocol.PROTEUS, + ConversationVerificationStatus.VERIFIED + ) + val (_, viewModel) = ConversationInfoViewModelArrangement() + .withVerificationStatus(result) + .withSelfUser() + .arrange() + + // then + assertEquals( + result, + viewModel.conversationInfoViewState.verificationStatus + ) + } + + @Test + fun `given Failure while getting an MLS conversation's verification status, then mlsVerificationStatus is null`() = runTest { + // Given + val (_, viewModel) = ConversationInfoViewModelArrangement() + .withVerificationStatus(ConversationVerificationStatusResult.Failure(StorageFailure.DataNotFound)) + .withSelfUser() + .arrange() + + // then + assertEquals( + null, + viewModel.conversationInfoViewState.verificationStatus + ) + } + + @Test + fun `given a not-verified Proteus conversation, then proteusVerificationStatus is not verified`() = runTest { + // Given + val result = ConversationVerificationStatusResult.Success( + ConversationProtocol.PROTEUS, + ConversationVerificationStatus.NOT_VERIFIED + ) + val (_, viewModel) = ConversationInfoViewModelArrangement() + .withVerificationStatus( + result + ) + .withSelfUser() + .arrange() + + // then + assertEquals( + result, + viewModel.conversationInfoViewState.verificationStatus + ) + } } From 24f9c778ac219f2f433be10ac0eafb4a17f2215e Mon Sep 17 00:00:00 2001 From: Vitor Hugo Schwaab Date: Mon, 24 Jul 2023 09:49:29 +0200 Subject: [PATCH 08/12] chore(deps): upgrade kotlin to 1.9.0 (#1992) --- buildSrc/build.gradle.kts | 2 +- gradle/libs.versions.toml | 5 ++--- kalium | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 1a08e63a0ff..53831dab5a6 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -19,7 +19,7 @@ */ private object Dependencies { - const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.21" + const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0" const val detektGradlePlugin = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.19.0" const val junit = "junit:junit:4.13" const val kluent = "org.amshove.kluent:kluent:1.73" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 96ef7241886..1e36c37fa8d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,11 +3,10 @@ gradle = "7.6.1" # Kotlin -kotlin = "1.8.21" +kotlin = "1.9.0" # KotlinX coroutines = "1.7.1" -ktx = "1.8.0" ktx-dateTime = "0.4.0" ktx-immutableCollections = "0.3.5" ktx-serialization = "1.3.2" @@ -38,7 +37,7 @@ androidx-browser = "1.3.0" compose = "1.5.0-beta03" compose-material = "1.4.3" compose-activity = "1.6.1" -compose-compiler = "1.4.7" +compose-compiler = "1.5.0" compose-constraint = "1.0.1" compose-material3 = "1.1.0" compose-navigation = "2.6.0" diff --git a/kalium b/kalium index d6fae6207ba..d3c3fc45f0f 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit d6fae6207ba4da0ef4337f16d18121e39419ab85 +Subproject commit d3c3fc45f0fa324fec49209cc1a0b301af089004 From 0150d940277d99025bcdeaea1d0e1af5f9070450 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 11:41:10 +0200 Subject: [PATCH 09/12] chore(deps): bump androidx.core:core-splashscreen from 1.0.0 to 1.0.1 (#1994) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1e36c37fa8d..e085f6119b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ androidx-jetpack = "1.1.0" androidx-lifecycle = "2.6.1" androidx-paging3 = "3.1.1" androidx-paging3Compose = "1.0.0-alpha18" -androidx-splashscreen = "1.0.0" +androidx-splashscreen = "1.0.1" androidx-workManager = "2.8.1" androidx-browser = "1.3.0" From a5f5571d07e0350983e75245162f3541d11f093e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 13:01:58 +0200 Subject: [PATCH 10/12] chore(deps): bump io.gitlab.arturbosch.detekt:detekt-gradle-plugin from 1.19.0 to 1.23.0 (#1995) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 53831dab5a6..cdd07df7249 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -20,7 +20,7 @@ private object Dependencies { const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0" - const val detektGradlePlugin = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.19.0" + const val detektGradlePlugin = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.0" const val junit = "junit:junit:4.13" const val kluent = "org.amshove.kluent:kluent:1.73" const val hilt = "com.google.dagger:hilt-android-gradle-plugin:2.47" From 9b65bafe653536f4337a15d5006ef2f2b3d27197 Mon Sep 17 00:00:00 2001 From: Tommaso Piazza <196761+tmspzz@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:19:52 +0200 Subject: [PATCH 11/12] chore: update kalium ref --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index d3c3fc45f0f..8572b17509e 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit d3c3fc45f0fa324fec49209cc1a0b301af089004 +Subproject commit 8572b17509e429ae845f82316973c1d13459c8ea From 398b709478b4b02107f833cceeee6a4ea9f3e6e3 Mon Sep 17 00:00:00 2001 From: Mojtaba Chenani Date: Mon, 24 Jul 2023 15:26:09 +0200 Subject: [PATCH 12/12] chore: bump version to 4.4.0 --- build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt b/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt index 417d71464a5..0ab7a298edb 100644 --- a/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt +++ b/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt @@ -25,6 +25,6 @@ object AndroidSdk { object AndroidApp { const val id = "com.wire.android" - const val versionName = "4.3.0" + const val versionName = "4.4.0" val versionCode = Versionizer().versionCode }