diff --git a/.github/workflows/build-edge-env.yml b/.github/workflows/build-edge-env.yml index 6d1de717470..3b091321437 100644 --- a/.github/workflows/build-edge-env.yml +++ b/.github/workflows/build-edge-env.yml @@ -95,4 +95,5 @@ jobs: serviceAccountJson: service_account.json packageName: com.wire.internal releaseFiles: app/build/outputs/bundle/internalCompat/*.aab - track: alpha + track: production + status: completed diff --git a/app/src/main/kotlin/com/wire/android/model/UserAvatarData.kt b/app/src/main/kotlin/com/wire/android/model/UserAvatarData.kt index 5d49d78d5d3..372e2ee474f 100644 --- a/app/src/main/kotlin/com/wire/android/model/UserAvatarData.kt +++ b/app/src/main/kotlin/com/wire/android/model/UserAvatarData.kt @@ -19,6 +19,7 @@ package com.wire.android.model import androidx.compose.runtime.Stable +import com.wire.android.R import com.wire.android.ui.home.conversationslist.model.Membership import com.wire.android.util.EMPTY import com.wire.kalium.logic.data.user.ConnectionState @@ -37,6 +38,13 @@ data class UserAvatarData( return asset == null && nameBasedAvatar != null && nameBasedAvatar.initials.isEmpty().not() && membership != Membership.Service } + + fun getAvailabilityStatusDescriptionId(): Int? = when (availabilityStatus) { + UserAvailabilityStatus.NONE -> null + UserAvailabilityStatus.AVAILABLE -> R.string.user_profile_status_available + UserAvailabilityStatus.AWAY -> R.string.user_profile_status_away + UserAvailabilityStatus.BUSY -> R.string.user_profile_status_busy + } } /** diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreateAccountOverviewParams.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreateAccountOverviewParams.kt index 51d3d2336e0..d59243c3c77 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreateAccountOverviewParams.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreateAccountOverviewParams.kt @@ -26,5 +26,6 @@ data class CreateAccountOverviewParams( val contentText: String = "", @DrawableRes val contentIconResId: Int = 0, val learnMoreText: String = "", - val learnMoreUrl: String = "" + val learnMoreUrl: String = "", + val isContentTextSemanticAccessible: Boolean = false ) diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreatePersonalAccountOverviewScreen.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreatePersonalAccountOverviewScreen.kt index ba76da0c892..7e2237c1ed3 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreatePersonalAccountOverviewScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/create/overview/CreatePersonalAccountOverviewScreen.kt @@ -109,7 +109,8 @@ fun CreateTeamAccountOverviewScreen( contentText = stringResource(id = overviewResources.overviewContentTextResId), contentIconResId = overviewResources.overviewContentIconResId, learnMoreText = stringResource(id = overviewResources.overviewLearnMoreTextResId), - learnMoreUrl = viewModel.learnMoreUrl() + learnMoreUrl = viewModel.learnMoreUrl(), + isContentTextSemanticAccessible = true ) ) } @@ -193,7 +194,15 @@ private fun OverviewTexts( text = overviewParams.contentText, style = MaterialTheme.wireTypography.body02, textAlign = TextAlign.Center, - modifier = Modifier.fillMaxWidth().clearAndSetSemantics {} + modifier = Modifier + .fillMaxWidth() + .run { + if (overviewParams.isContentTextSemanticAccessible) { + this + } else { + clearAndSetSemantics {} + } + } ) Text( text = overviewParams.learnMoreText, diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt index a3a940da9e5..b0a7d95a2b4 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/devices/DeviceItem.kt @@ -42,6 +42,8 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.wire.android.BuildConfig @@ -189,13 +191,22 @@ private fun ColumnScope.DeviceItemTexts( .fillMaxWidth() .shimmerPlaceholder(visible = placeholder) ) { + val deviceName = device.name.asString() + val shouldAddNotVerifiedLabel = shouldShowVerifyLabel && !shouldShowE2EIInfo && !(device.isVerifiedProteus && !isCurrentClient) + val semantic = if (shouldAddNotVerifiedLabel) { + val notVerifiedLabel = stringResource(R.string.label_client_unverified) + Modifier.clearAndSetSemantics { contentDescription = "$deviceName, $notVerifiedLabel" } + } else { + Modifier + } Text( style = MaterialTheme.wireTypography.body02, color = MaterialTheme.wireColorScheme.onBackground, - text = device.name.asString(), + text = deviceName, modifier = Modifier .wrapContentWidth() .shimmerPlaceholder(visible = placeholder) + .then(semantic) ) if (shouldShowVerifyLabel) { if (shouldShowE2EIInfo) { @@ -223,6 +234,16 @@ private fun ColumnScope.DeviceItemTexts( Spacer(modifier = Modifier.height(MaterialTheme.wireDimensions.removeDeviceItemTitleVerticalPadding)) + MLSDetails(device, placeholder) + + ProteusDetails(device, placeholder) +} + +@Composable +private fun MLSDetails( + device: Device, + placeholder: Boolean +) { device.mlsClientIdentity?.let { identity -> Text( style = MaterialTheme.wireTypography.subline01, @@ -238,7 +259,13 @@ private fun ColumnScope.DeviceItemTexts( .shimmerPlaceholder(visible = placeholder) ) } +} +@Composable +private fun ProteusDetails( + device: Device, + placeholder: Boolean +) { val proteusDetails: String = if (!device.registrationTime.isNullOrBlank()) { if (device.lastActiveInWholeWeeks != null) { stringResource( diff --git a/app/src/main/kotlin/com/wire/android/ui/common/UserProfileAvatar.kt b/app/src/main/kotlin/com/wire/android/ui/common/UserProfileAvatar.kt index abe895cabba..ccaf7a8eb44 100644 --- a/app/src/main/kotlin/com/wire/android/ui/common/UserProfileAvatar.kt +++ b/app/src/main/kotlin/com/wire/android/ui/common/UserProfileAvatar.kt @@ -57,7 +57,10 @@ import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -248,12 +251,19 @@ private fun DefaultInitialsAvatar( type: UserProfileAvatarType, size: Dp, modifier: Modifier = Modifier, + contentDescription: String? = null ) { - val contentDescription = stringResource(R.string.content_description_user_avatar) + val semantics = if (contentDescription != null) { + Modifier.semantics { + this.contentDescription = contentDescription + this.role = Role.Image + } + } else { + Modifier.clearAndSetSemantics { } + } Box( contentAlignment = Alignment.Center, modifier = modifier - .semantics { this.contentDescription = contentDescription } .size(size) .clip(CircleShape) .background( @@ -266,6 +276,7 @@ private fun DefaultInitialsAvatar( ) } ) + .then(semantics) ) { Text( text = nameBasedAvatar.initials, diff --git a/app/src/main/kotlin/com/wire/android/ui/common/WireDropDown.kt b/app/src/main/kotlin/com/wire/android/ui/common/WireDropDown.kt index 42d3a910900..d05b7c7e741 100644 --- a/app/src/main/kotlin/com/wire/android/ui/common/WireDropDown.kt +++ b/app/src/main/kotlin/com/wire/android/ui/common/WireDropDown.kt @@ -56,6 +56,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.onClick +import androidx.compose.ui.semantics.paneTitle import androidx.compose.ui.semantics.selected import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview @@ -164,6 +165,8 @@ private fun MenuPopUp( hidePopUp: () -> Unit, onChange: (selectedIndex: Int) -> Unit ) { + val dropdownDescription = stringResource(R.string.content_description_drop_down) + MaterialTheme(shapes = MaterialTheme.shapes.copy(extraSmall = shape)) { // we want PopUp to cover the selection field, so we set this offset. // "- 8.dp" is because DropdownMenu has inner top padding, which can't be changed, @@ -178,14 +181,15 @@ private fun MenuPopUp( .width(with(LocalDensity.current) { textFieldWidth.width.toDp() }) .background(color = MaterialTheme.wireColorScheme.secondaryButtonEnabled) .border(width = 1.dp, color = borderColor, shape) + .semantics { paneTitle = dropdownDescription } ) { SelectionField( - Modifier.clickable(onClickLabel = stringResource(R.string.content_description_close_dropdown)) { hidePopUp() }, leadingCompose, selectedIndex, selectionText, - arrowRotation + arrowRotation, + Modifier.clickable(onClickLabel = stringResource(R.string.content_description_close_dropdown)) { hidePopUp() } ) List(items.size) { index -> @@ -210,11 +214,11 @@ private fun MenuPopUp( @Composable private fun SelectionField( - modifier: Modifier = Modifier, leadingCompose: @Composable ((index: Int) -> Unit)?, selectedIndex: Int, text: String, - arrowRotation: Float + arrowRotation: Float, + modifier: Modifier = Modifier ) { Row( modifier @@ -262,6 +266,7 @@ private fun DropdownItem( onClick: () -> Unit ) { val selectLabel = stringResource(R.string.content_description_select_label) + val closeDropdownLabel = stringResource(R.string.content_description_close_dropdown) return DropdownMenuItem( text = { Text( @@ -281,8 +286,12 @@ private fun DropdownItem( onClick = onClick, modifier = Modifier .semantics { - onClick(selectLabel) { false } - if (isSelected) selected = true + if (isSelected) { + selected = true + onClick(closeDropdownLabel) { false } + } else { + onClick(selectLabel) { false } + } } .background( color = if (isSelected) MaterialTheme.wireColorScheme.secondaryButtonSelected diff --git a/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt index 74dcec0ba5b..282fac94e23 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt @@ -305,7 +305,7 @@ fun HomeContent( } }, collapsingEnabled = !searchBarState.isSearchActive, - contentLazyListState = homeStateHolder.currentLazyListState, + contentLazyListState = homeStateHolder.lazyListStateFor(currentNavigationItem), content = { /** * This "if" is a workaround, otherwise it can crash because of the SubcomposeLayout's nature. diff --git a/app/src/main/kotlin/com/wire/android/ui/home/HomeStateHolder.kt b/app/src/main/kotlin/com/wire/android/ui/home/HomeStateHolder.kt index 459a3127f52..034c10e9250 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/HomeStateHolder.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/HomeStateHolder.kt @@ -24,6 +24,8 @@ import androidx.compose.material3.DrawerState import androidx.compose.material3.DrawerValue import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -42,12 +44,15 @@ class HomeStateHolder( val coroutineScope: CoroutineScope, val navController: NavHostController, val drawerState: DrawerState, - val currentNavigationItem: HomeDestination, val searchBarState: SearchBarState, val navigator: Navigator, - lazyListStates: Map, + private val currentNavigationItemState: State, + private val lazyListStates: Map, ) { - val currentLazyListState = lazyListStates[currentNavigationItem] ?: error("No LazyListState found for $currentNavigationItem") + val currentNavigationItem + get() = currentNavigationItemState.value + fun lazyListStateFor(destination: HomeDestination): LazyListState = + lazyListStates[destination] ?: error("No LazyListState found for $destination") fun closeDrawer() { coroutineScope.launch { @@ -73,23 +78,22 @@ fun rememberHomeScreenState( ): HomeStateHolder { val searchBarState = rememberSearchbarState() val navBackStackEntry by navController.currentBackStackEntryAsState() - val currentRoute = navBackStackEntry?.destination?.route - val currentNavigationItem = currentRoute?.let { HomeDestination.fromRoute(it) } ?: HomeDestination.Conversations + val currentNavigationItemState = remember { + derivedStateOf { + navBackStackEntry?.destination?.route?.let { HomeDestination.fromRoute(it) } ?: HomeDestination.Conversations + } + } val lazyListStates = HomeDestination.values().associateWith { rememberLazyListState() } - val homeState = remember( - currentNavigationItem - ) { + return remember { HomeStateHolder( - coroutineScope, - navController, - drawerState, - currentNavigationItem, - searchBarState, - navigator, - lazyListStates + coroutineScope = coroutineScope, + navController = navController, + drawerState = drawerState, + searchBarState = searchBarState, + navigator = navigator, + currentNavigationItemState = currentNavigationItemState, + lazyListStates = lazyListStates ) } - - return homeState } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/archive/ArchiveScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/archive/ArchiveScreen.kt index 52b0c0f2bc1..597f2d26390 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/archive/ArchiveScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/archive/ArchiveScreen.kt @@ -20,6 +20,7 @@ package com.wire.android.ui.home.archive import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.runtime.Composable +import com.wire.android.navigation.HomeDestination import com.wire.android.navigation.HomeNavGraph import com.wire.android.navigation.WireDestination import com.wire.android.navigation.rememberNavigator @@ -42,7 +43,7 @@ fun ArchiveScreen(homeStateHolder: HomeStateHolder) { navigator = navigator, searchBarState = searchBarState, conversationsSource = ConversationsSource.ARCHIVE, - lazyListState = currentLazyListState, + lazyListState = lazyListStateFor(HomeDestination.Archive), emptyListContent = { ArchiveEmptyContent() } ) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/participants/ConversationParticipantItem.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/participants/ConversationParticipantItem.kt index 846eedf887a..6fb983b7ae7 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/participants/ConversationParticipantItem.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/details/participants/ConversationParticipantItem.kt @@ -28,6 +28,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import com.wire.android.BuildConfig import com.wire.android.R import com.wire.android.model.Clickable @@ -124,10 +126,18 @@ fun ConversationParticipantItem( } }, subtitle = { + val userName = processUsername(uiParticipant) + // Availability status should be called after username by TalkBack + val subtitleModifier = uiParticipant.avatarData.getAvailabilityStatusDescriptionId()?.let { + val contentDescription = stringResource(it) + Modifier.semantics { this.contentDescription = "$userName, $contentDescription" } + } ?: Modifier + HighlightSubtitle( - subTitle = processUsername(uiParticipant), + subTitle = userName, searchQuery = searchQuery, - prefix = processUsernamePrefix(uiParticipant) + prefix = processUsernamePrefix(uiParticipant), + modifier = subtitleModifier ) }, actions = { 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 3495deb7662..5e36411a498 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 @@ -25,6 +25,7 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.wire.android.R import com.wire.android.appLogger +import com.wire.android.di.CurrentAccount import com.wire.android.model.ImageAsset import com.wire.android.navigation.SavedStateViewModel import com.wire.android.ui.home.conversations.ConversationNavArgs @@ -40,9 +41,7 @@ import com.wire.kalium.logic.data.user.ConnectionState import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseCase import com.wire.kalium.logic.feature.e2ei.usecase.FetchConversationMLSVerificationStatusUseCase -import com.wire.kalium.logic.feature.user.GetSelfUserUseCase import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import javax.inject.Inject @@ -52,9 +51,9 @@ class ConversationInfoViewModel @Inject constructor( private val qualifiedIdMapper: QualifiedIdMapper, override val savedStateHandle: SavedStateHandle, private val observeConversationDetails: ObserveConversationDetailsUseCase, - private val observerSelfUser: GetSelfUserUseCase, private val fetchConversationMLSVerificationStatus: FetchConversationMLSVerificationStatusUseCase, private val wireSessionImageLoader: WireSessionImageLoader, + @CurrentAccount private val selfUserId: UserId, ) : SavedStateViewModel(savedStateHandle) { private val conversationNavArgs: ConversationNavArgs = savedStateHandle.navArgs() @@ -62,10 +61,7 @@ class ConversationInfoViewModel @Inject constructor( var conversationInfoViewState by mutableStateOf(ConversationInfoViewState(conversationId)) - private lateinit var selfUserId: UserId - init { - getSelfUserId() fetchMLSVerificationStatus() } @@ -75,12 +71,6 @@ class ConversationInfoViewModel @Inject constructor( } } - private fun getSelfUserId() { - viewModelScope.launch { - selfUserId = observerSelfUser().first().id - } - } - /* If this would be collected in the scope of this ViewModel (in `init` for instance) then there would be a race condition. [MessageComposerViewModel] handles the navigating back after removing a group and here it would navigate to home if the group diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/HighLightSubtTitle.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/HighLightSubtTitle.kt index 1909cbda730..12e1a7c4d4a 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/HighLightSubtTitle.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/HighLightSubtTitle.kt @@ -21,6 +21,7 @@ package com.wire.android.ui.home.conversations.search import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextOverflow @@ -33,6 +34,7 @@ import com.wire.android.util.QueryMatchExtractor @Composable fun HighlightSubtitle( subTitle: String, + modifier: Modifier = Modifier, searchQuery: String = String.EMPTY, prefix: String = "@" ) { @@ -76,6 +78,7 @@ fun HighlightSubtitle( } } }, + modifier = modifier, maxLines = 1, overflow = TextOverflow.Ellipsis ) @@ -85,7 +88,8 @@ fun HighlightSubtitle( style = MaterialTheme.wireTypography.subline01, color = MaterialTheme.wireColorScheme.secondaryText, maxLines = 1, - overflow = TextOverflow.Ellipsis + overflow = TextOverflow.Ellipsis, + modifier = modifier ) } } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/SearchUsersAndServicesScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/SearchUsersAndServicesScreen.kt index ff3801d6bf9..743832d4877 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/SearchUsersAndServicesScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/search/SearchUsersAndServicesScreen.kt @@ -117,8 +117,11 @@ fun SearchUsersAndServicesScreen( SearchPeopleScreenType.CONVERSATION_DETAILS -> NavigationIconType.Close(R.string.content_description_add_participants_close) - SearchPeopleScreenType.NEW_CONVERSATION -> NavigationIconType.Close() - SearchPeopleScreenType.NEW_GROUP_CONVERSATION -> NavigationIconType.Back() + SearchPeopleScreenType.NEW_CONVERSATION -> + NavigationIconType.Close(R.string.content_description_new_conversation_close_btn) + + SearchPeopleScreenType.NEW_GROUP_CONVERSATION -> + NavigationIconType.Back(R.string.content_description_new_group_conversation_back_btn) }, onNavigationPressed = onClose ) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/all/AllConversationsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/all/AllConversationsScreen.kt index a1b757e968c..f354558d5cf 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/all/AllConversationsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/all/AllConversationsScreen.kt @@ -20,6 +20,7 @@ package com.wire.android.ui.home.conversationslist.all import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.runtime.Composable +import com.wire.android.navigation.HomeDestination import com.wire.android.navigation.HomeNavGraph import com.wire.android.navigation.WireDestination import com.wire.android.navigation.rememberNavigator @@ -42,7 +43,7 @@ fun AllConversationsScreen(homeStateHolder: HomeStateHolder) { navigator = navigator, searchBarState = searchBarState, conversationsSource = ConversationsSource.MAIN, - lazyListState = currentLazyListState, + lazyListState = lazyListStateFor(HomeDestination.Conversations), emptyListContent = { AllConversationsEmptyContent() } ) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/common/ConversationItemFactory.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/common/ConversationItemFactory.kt index 44ac89e3f7a..571b408bab4 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/common/ConversationItemFactory.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/common/ConversationItemFactory.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics import com.wire.android.R import com.wire.android.model.Clickable import com.wire.android.model.UserAvatarData @@ -75,16 +76,24 @@ fun ConversationItemFactory( ) { val openConversationOptionDescription = stringResource(R.string.content_description_conversation_details_more_btn) val openUserProfileDescription = stringResource(R.string.content_description_open_user_profile_label) + val acceptOrIgnoreDescription = stringResource(R.string.content_description_accept_or_ignore_connection_label) val openConversationDescription = stringResource(R.string.content_description_open_conversation_label) val onConversationItemClick = remember(conversation) { when (val lastEvent = conversation.lastMessageContent) { - is UILastMessageContent.Connection -> Clickable( - enabled = true, - onClick = { openUserProfile(lastEvent.userId) }, - onLongClick = null, - onClickDescription = openUserProfileDescription, - onLongClickDescription = null - ) + is UILastMessageContent.Connection -> { + val onClickDescription = if (conversation.badgeEventType == BadgeEventType.ReceivedConnectionRequest) { + acceptOrIgnoreDescription + } else { + openUserProfileDescription + } + Clickable( + enabled = true, + onClick = { openUserProfile(lastEvent.userId) }, + onLongClick = null, + onClickDescription = onClickDescription, + onLongClickDescription = null + ) + } else -> Clickable( enabled = true, @@ -97,7 +106,7 @@ fun ConversationItemFactory( } GeneralConversationItem( - modifier = modifier, + modifier = modifier.semantics(mergeDescendants = true) { }, conversation = conversation, isSelectable = isSelectableItem, isChecked = isChecked, diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageActions.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageActions.kt index 17f9ad78bbc..30f5621a889 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageActions.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/MessageActions.kt @@ -108,7 +108,7 @@ fun MessageEditActions( WireTertiaryIconButton( onButtonClicked = onEditCancelButtonClicked, iconResource = R.drawable.ic_close, - contentDescription = R.string.content_description_close_button, + contentDescription = R.string.label_close, shape = CircleShape, minSize = MaterialTheme.wireDimensions.buttonCircleMinSize, minClickableSize = MaterialTheme.wireDimensions.buttonMinClickableSize, diff --git a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/RecordAudioButtons.kt b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/RecordAudioButtons.kt index 33e010dc9b1..487e0cc5171 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/RecordAudioButtons.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/recordaudio/RecordAudioButtons.kt @@ -74,7 +74,7 @@ fun RecordAudioButtonClose( WireTertiaryIconButton( onButtonClicked = onClick, iconResource = R.drawable.ic_close, - contentDescription = R.string.content_description_close_button, + contentDescription = R.string.label_close, shape = CircleShape, minSize = MaterialTheme.wireDimensions.buttonCircleMinSize, minClickableSize = MaterialTheme.wireDimensions.buttonMinClickableSize, diff --git a/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt index 3617c3028d5..4d6892641d2 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt @@ -33,6 +33,7 @@ import com.wire.android.R import com.wire.android.appLogger import com.wire.android.model.Clickable import com.wire.android.navigation.BackStackMode +import com.wire.android.navigation.HomeDestination import com.wire.android.navigation.HomeNavGraph import com.wire.android.navigation.NavigationCommand import com.wire.android.navigation.WireDestination @@ -62,7 +63,7 @@ fun SettingsScreen( val context = LocalContext.current SettingsScreenContent( - lazyListState = homeStateHolder.currentLazyListState, + lazyListState = homeStateHolder.lazyListStateFor(HomeDestination.Settings), settingsState = viewModel.state, onItemClicked = remember { { diff --git a/app/src/main/kotlin/com/wire/android/ui/home/whatsnew/WhatsNewScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/whatsnew/WhatsNewScreen.kt index 049e3021265..de06e11106b 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/whatsnew/WhatsNewScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/whatsnew/WhatsNewScreen.kt @@ -33,6 +33,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.wire.android.BuildConfig import com.wire.android.R import com.wire.android.model.Clickable +import com.wire.android.navigation.HomeDestination import com.wire.android.navigation.HomeNavGraph import com.wire.android.navigation.NavigationCommand import com.wire.android.navigation.WireDestination @@ -51,7 +52,7 @@ fun WhatsNewScreen( val context = LocalContext.current WhatsNewScreenContent( state = whatsNewViewModel.state, - lazyListState = homeStateHolder.currentLazyListState, + lazyListState = homeStateHolder.lazyListStateFor(HomeDestination.WhatsNew), onItemClicked = remember { { it.direction.handleNavigation( diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/dialog/LogoutOptionsDialog.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/dialog/LogoutOptionsDialog.kt index 221b012bcb6..b335e3713e8 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/dialog/LogoutOptionsDialog.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/dialog/LogoutOptionsDialog.kt @@ -52,7 +52,8 @@ fun LogoutOptionsDialog( dismissButtonProperties = WireDialogButtonProperties( onClick = dialogState::dismiss, text = stringResource(id = R.string.label_cancel), - state = WireButtonState.Default + state = WireButtonState.Default, + description = stringResource(R.string.dialog_logout_wipe_data_cancel_description) ), optionButton1Properties = WireDialogButtonProperties( onClick = remember(state) { { logout(state.shouldWipeData).also { dialogState.dismiss() } } }, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0e080e0598c..ecf54741471 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -211,14 +211,18 @@ toggle setting Go back to conversation details Go back to conversation details + accept or ignore the request open profile open conversation open service change it open link Alert + Dropdown close dropdown open notification settings + Close new conversation view + Go back to new conversation view Go back to new conversation view Type group name Conversation options @@ -618,6 +622,7 @@ Clear Data? Delete all your personal information and conversations on this device + Cancel logout Set yourself to Available You will appear as Available to other people. You will receive notifications for incoming calls and for messages according to the Notifications setting in each conversation. 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 397c3e3107b..931b5f6280d 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 @@ -32,7 +32,6 @@ import com.wire.kalium.logic.data.id.QualifiedIdMapper import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseCase import com.wire.kalium.logic.feature.e2ei.usecase.FetchConversationMLSVerificationStatusUseCase -import com.wire.kalium.logic.feature.user.GetSelfUserUseCase import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.every @@ -57,9 +56,6 @@ class ConversationInfoViewModelArrangement { @MockK lateinit var observeConversationDetails: ObserveConversationDetailsUseCase - @MockK - lateinit var observerSelfUser: GetSelfUserUseCase - @MockK lateinit var fetchConversationMLSVerificationStatus: FetchConversationMLSVerificationStatusUseCase @@ -74,9 +70,9 @@ class ConversationInfoViewModelArrangement { qualifiedIdMapper, savedStateHandle, observeConversationDetails, - observerSelfUser, fetchConversationMLSVerificationStatus, - wireSessionImageLoader + wireSessionImageLoader, + selfUserId = TestUser.SELF_USER_ID, ) } @@ -105,10 +101,6 @@ class ConversationInfoViewModelArrangement { coEvery { observeConversationDetails(any()) } returns flowOf(ObserveConversationDetailsUseCase.Result.Failure(failure)) } - suspend fun withSelfUser() = apply { - coEvery { observerSelfUser() } returns flowOf(TestUser.SELF_USER) - } - fun withMentionedUserId(id: UserId) = apply { every { qualifiedIdMapper.fromStringToQualifiedID(id.toString()) } returns id } 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 d4243d490e4..76132e209bb 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 @@ -47,7 +47,6 @@ class ConversationInfoViewModelTest { val groupConversationDetails = mockConversationDetailsGroup("Conversation Name Goes Here") val (_, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailUpdate(conversationDetails = groupConversationDetails) - .withSelfUser() .withMentionedUserId(TestUser.SELF_USER.id) .arrange() // When @@ -62,7 +61,6 @@ class ConversationInfoViewModelTest { val groupConversationDetails = mockConversationDetailsGroup("Conversation Name Goes Here") val (_, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailUpdate(conversationDetails = groupConversationDetails) - .withSelfUser() .withMentionedUserId(TestUser.OTHER_USER.id) .arrange() // When @@ -79,7 +77,6 @@ class ConversationInfoViewModelTest { .withConversationDetailUpdate( conversationDetails = oneToOneConversationDetails ) - .withSelfUser() .arrange() launch { viewModel.observeConversationDetails {} }.run { advanceUntilIdle() @@ -101,7 +98,6 @@ class ConversationInfoViewModelTest { .withConversationDetailUpdate( conversationDetails = oneToOneConversationDetails ) - .withSelfUser() .arrange() launch { viewModel.observeConversationDetails {} }.run { advanceUntilIdle() @@ -117,7 +113,6 @@ class ConversationInfoViewModelTest { val groupConversationDetails = mockConversationDetailsGroup("Conversation Name Goes Here") val (_, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailUpdate(conversationDetails = groupConversationDetails) - .withSelfUser() .arrange() launch { viewModel.observeConversationDetails {} }.run { advanceUntilIdle() @@ -140,7 +135,6 @@ class ConversationInfoViewModelTest { .withConversationDetailUpdate( conversationDetails = firstConversationDetails ) - .withSelfUser() .arrange() launch { viewModel.observeConversationDetails {} }.run { advanceUntilIdle() @@ -169,7 +163,6 @@ class ConversationInfoViewModelTest { runTest { // Given val (_, viewModel) = ConversationInfoViewModelArrangement() - .withSelfUser() .arrange() // When - Then @@ -185,7 +178,6 @@ class ConversationInfoViewModelTest { .withConversationDetailUpdate( conversationDetails = oneToOneConversationDetails ) - .withSelfUser() .arrange() launch { viewModel.observeConversationDetails {} }.run { advanceUntilIdle() @@ -202,7 +194,6 @@ class ConversationInfoViewModelTest { val otherUserAvatar = conversationDetails.otherUser.previewPicture val (_, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailUpdate(conversationDetails = conversationDetails) - .withSelfUser() .arrange() launch { viewModel.observeConversationDetails {} }.run { advanceUntilIdle() @@ -220,7 +211,6 @@ class ConversationInfoViewModelTest { val groupConversationDetails = mockConversationDetailsGroup("Conversation Name Goes Here") val (_, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailUpdate(conversationDetails = groupConversationDetails) - .withSelfUser() .arrange() // then @@ -244,7 +234,6 @@ class ConversationInfoViewModelTest { val groupConversationDetails = mockConversationDetailsGroup("Conversation Name Goes Here") val (_, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailUpdate(conversationDetails = groupConversationDetails) - .withSelfUser() .arrange() // then @@ -268,7 +257,6 @@ class ConversationInfoViewModelTest { val groupConversationDetails = mockConversationDetailsGroup("Conversation Name Goes Here") val (_, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailUpdate(conversationDetails = groupConversationDetails) - .withSelfUser() .arrange() // then @@ -290,7 +278,6 @@ class ConversationInfoViewModelTest { fun `given Failure while getting an MLS conversation's verification status, then mlsVerificationStatus is null`() = runTest { // Given val (_, viewModel) = ConversationInfoViewModelArrangement() - .withSelfUser() .arrange() // then @@ -309,7 +296,6 @@ class ConversationInfoViewModelTest { // Given val (arrangement, viewModel) = ConversationInfoViewModelArrangement() .withConversationDetailFailure(StorageFailure.DataNotFound) - .withSelfUser() .arrange() launch { viewModel.observeConversationDetails(arrangement.onNotFound) }.run { advanceUntilIdle() diff --git a/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt b/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt index a93b618ee19..51888ade39a 100644 --- a/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt +++ b/build-logic/plugins/src/main/kotlin/AndroidCoordinates.kt @@ -26,7 +26,7 @@ object AndroidSdk { object AndroidApp { const val id = "com.wire.android" - const val versionName = "4.9.0" + const val versionName = "4.9.1" val versionCode by lazy { Versionizer(_rootDir).versionCode } diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/WireDialog.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/WireDialog.kt index b4e0ab63aa6..c16829ab2df 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/WireDialog.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/WireDialog.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.paneTitle import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.AnnotatedString @@ -230,7 +231,7 @@ fun WireDialogContent( @Composable private fun TitleDialogSection(title: String, titleLoading: Boolean) { Row(verticalAlignment = Alignment.CenterVertically) { - Text(text = title, style = MaterialTheme.wireTypography.title02) + Text(text = title, style = MaterialTheme.wireTypography.title02, modifier = Modifier.semantics { heading() }) if (titleLoading) { WireCircularProgressIndicator(progressColor = MaterialTheme.wireColorScheme.onBackground) } @@ -281,13 +282,13 @@ private fun WireDialogButtonProperties?.getButton(modifier: Modifier = Modifier) Box(modifier = modifier) { when (type) { WireDialogButtonType.Primary -> - WirePrimaryButton(onClick = onClick, text = text, state = state, loading = loading) + WirePrimaryButton(onClick = onClick, text = text, state = state, loading = loading, description = description) WireDialogButtonType.Secondary -> - WireSecondaryButton(onClick = onClick, text = text, state = state, loading = loading) + WireSecondaryButton(onClick = onClick, text = text, state = state, loading = loading, description = description) WireDialogButtonType.Tertiary -> - WireTertiaryButton(onClick = onClick, text = text, state = state, loading = loading) + WireTertiaryButton(onClick = onClick, text = text, state = state, loading = loading, description = description) } } } @@ -300,7 +301,8 @@ data class WireDialogButtonProperties( val onClick: () -> Unit, val state: WireButtonState = WireButtonState.Default, val type: WireDialogButtonType = WireDialogButtonType.Secondary, - val loading: Boolean = false + val loading: Boolean = false, + val description: String? = null ) data class DialogTextSuffixLink(val linkText: String, val linkUrl: String) diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/bottomsheet/ModalSheetHeaderItem.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/bottomsheet/ModalSheetHeaderItem.kt index 1f00db1864c..f43ac73b191 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/bottomsheet/ModalSheetHeaderItem.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/bottomsheet/ModalSheetHeaderItem.kt @@ -30,7 +30,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.Dp import com.wire.android.ui.common.dimensions @@ -60,7 +60,7 @@ fun ModalSheetHeaderItem(header: MenuModalSheetHeader = MenuModalSheetHeader.Gon Text( text = header.title, style = MaterialTheme.wireTypography.title02, - modifier = Modifier.semantics { contentDescription = header.title } + modifier = Modifier.semantics { heading() } ) } WireDivider() diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireButton.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireButton.kt index 00b8e95b805..0e441d40c33 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireButton.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireButton.kt @@ -33,7 +33,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonElevation -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -49,6 +48,8 @@ import androidx.compose.ui.graphics.Shape import androidx.compose.ui.layout.layout import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.TextStyle @@ -65,7 +66,6 @@ import com.wire.android.ui.theme.wireTypography import java.lang.Integer.max import kotlin.math.roundToInt -@OptIn(ExperimentalMaterial3Api::class) @Composable fun WireButton( onClick: () -> Unit, @@ -91,7 +91,8 @@ fun WireButton( vertical = MaterialTheme.wireDimensions.buttonVerticalContentPadding ), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - onClickDescription: String? = null + onClickDescription: String? = null, + description: String? = null ) { val border = when { borderWidth > 0.dp -> BorderStroke(width = borderWidth, color = colors.outlineColor(state).value) @@ -124,7 +125,10 @@ fun WireButton( placeable.place(centerX, centerY) } } - .semantics { onClickDescription?.let { onClick(it) { false } } }, + .semantics { + onClickDescription?.let { onClick(it) { false } } + description?.let { contentDescription = description } + }, enabled = state != WireButtonState.Disabled, interactionSource = interactionSource, elevation = elevation, @@ -144,6 +148,7 @@ fun WireButton( textStyle = textStyle, state = state, colors = colors, + semanticIgnoreText = !description.isNullOrEmpty() ) } } @@ -161,6 +166,7 @@ private fun InnerButtonBox( textStyle: TextStyle = MaterialTheme.wireTypography.button03, state: WireButtonState = WireButtonState.Default, colors: WireButtonColors = wirePrimaryButtonColors(), + semanticIgnoreText: Boolean = false ) { val contentColor = colors.contentColor(state).value val leadingItem: (@Composable () -> Unit) = { leadingIcon?.let { Tint(contentColor = contentColor, content = it) } } @@ -198,7 +204,9 @@ private fun InnerButtonBox( ) { if (leadingIconAlignment == IconAlignment.Center) leadingItem() if (!text.isNullOrEmpty()) { + val modifier = if (semanticIgnoreText) Modifier.clearAndSetSemantics { } else Modifier Text( + modifier = modifier, text = text, style = textStyle, color = contentColor diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt index 8a5ae5ec23b..51bf9059129 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt @@ -33,6 +33,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview @@ -53,13 +54,14 @@ fun WireItemLabel( contentDescription: String = text ) = Box( modifier = modifier - .border(width = 1.dp, color = MaterialTheme.wireColorScheme.divider, shape = shape) + .border(width = 1.dp, color = MaterialTheme.wireColorScheme.secondaryButtonDisabledOutline, shape = shape) .padding(contentPadding) - .semantics(mergeDescendants = true) { this.contentDescription = contentDescription } + .semantics { this.contentDescription = contentDescription } .wrapContentWidth() .wrapContentHeight(), ) { Text( + modifier = Modifier.clearAndSetSemantics { }, text = text, style = MaterialTheme.wireTypography.label02, ) diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WirePrimaryButton.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WirePrimaryButton.kt index 48b08791764..7b1dc2af159 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WirePrimaryButton.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WirePrimaryButton.kt @@ -71,7 +71,8 @@ fun WirePrimaryButton( vertical = MaterialTheme.wireDimensions.buttonVerticalContentPadding ), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - onClickDescription: String? = null + onClickDescription: String? = null, + description: String? = null ) = WireButton( onClick = onClick, loading = loading, @@ -93,7 +94,8 @@ fun WirePrimaryButton( contentPadding = contentPadding, interactionSource = interactionSource, modifier = modifier, - onClickDescription = onClickDescription + onClickDescription = onClickDescription, + description = description ) @Preview(name = "Default WirePrimaryButton") diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireSecondaryButton.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireSecondaryButton.kt index 4045fa2d517..9fdf93fdb77 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireSecondaryButton.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireSecondaryButton.kt @@ -70,7 +70,8 @@ fun WireSecondaryButton( vertical = MaterialTheme.wireDimensions.buttonVerticalContentPadding ), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - onClickDescription: String? = null + onClickDescription: String? = null, + description: String? = null ) = WireButton( onClick = onClick, loading = loading, @@ -92,7 +93,8 @@ fun WireSecondaryButton( contentPadding = contentPadding, interactionSource = interactionSource, modifier = modifier, - onClickDescription = onClickDescription + onClickDescription = onClickDescription, + description = description ) @Preview(name = "Default WireSecondaryButton") diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireTertiaryButton.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireTertiaryButton.kt index bcd77ea67bb..80696e05ecf 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireTertiaryButton.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireTertiaryButton.kt @@ -66,7 +66,8 @@ fun WireTertiaryButton( vertical = MaterialTheme.wireDimensions.buttonVerticalContentPadding ), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - onClickDescription: String? = null + onClickDescription: String? = null, + description: String? = null ) = WireButton( onClick = onClick, loading = loading, @@ -88,7 +89,8 @@ fun WireTertiaryButton( contentPadding = contentPadding, interactionSource = interactionSource, modifier = modifier, - onClickDescription = onClickDescription + onClickDescription = onClickDescription, + description = description ) @Preview(name = "Default WireSecondaryButton") diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/topappbar/NavigationIconButton.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/topappbar/NavigationIconButton.kt index f0618adca53..dd0bb92a1b4 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/topappbar/NavigationIconButton.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/topappbar/NavigationIconButton.kt @@ -45,10 +45,10 @@ fun BackNavigationIconButton(onBackButtonClick: () -> Unit) { } sealed class NavigationIconType(val icon: ImageVector, @StringRes open val contentDescription: Int) { - data class Back(@StringRes override val contentDescription: Int = R.string.content_description_back_button) : + data class Back(@StringRes override val contentDescription: Int = R.string.content_description_left_arrow) : NavigationIconType(Icons.AutoMirrored.Filled.ArrowBack, contentDescription) - data class Close(@StringRes override val contentDescription: Int = R.string.content_description_close_button) : + data class Close(@StringRes override val contentDescription: Int = R.string.content_description_close) : NavigationIconType(Icons.Filled.Close, contentDescription) data object Menu : NavigationIconType(Icons.Filled.Menu, R.string.content_description_menu_button) diff --git a/core/ui-common/src/main/res/values/strings.xml b/core/ui-common/src/main/res/values/strings.xml index 88bc5693363..ae450d738d4 100644 --- a/core/ui-common/src/main/res/values/strings.xml +++ b/core/ui-common/src/main/res/values/strings.xml @@ -20,7 +20,9 @@ Please wait until the app is synchronized Please wait until the Internet connection is restored Back button + Go Back Close button + Close Main navigation Drop down arrow pending approval of connection request diff --git a/default.json b/default.json index 94c1f143236..5787cb41974 100644 --- a/default.json +++ b/default.json @@ -68,7 +68,8 @@ "encrypt_proteus_storage": true, "analytics_enabled": true, "analytics_app_key": "8ffae535f1836ed5f58fd5c8a11c00eca07c5438", - "analytics_server_url": "https://countly.wire.com/" + "analytics_server_url": "https://countly.wire.com/", + "paginated_conversation_list_enabled": true }, "internal": { "application_id": "com.wire.internal", @@ -80,7 +81,8 @@ "analytics_enabled": true, "picture_in_picture_enabled": true, "analytics_app_key": "8ffae535f1836ed5f58fd5c8a11c00eca07c5438", - "analytics_server_url": "https://countly.wire.com/" + "analytics_server_url": "https://countly.wire.com/", + "paginated_conversation_list_enabled": true }, "fdroid": { "application_id": "com.wire", diff --git a/kalium b/kalium index 83207c730fd..7440f44a015 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 83207c730fd36ac4aa2c6fdc11338dd18fc51333 +Subproject commit 7440f44a0153dd4527e88991610db0260fab4762