From 22aff6bb0d97fc671920c6722c6e6c60d5ba10eb Mon Sep 17 00:00:00 2001 From: Boris Safonov Date: Fri, 22 Nov 2024 13:42:13 +0200 Subject: [PATCH 1/2] fix: Accessibility strings founded issues --- .../com/wire/android/model/UserAvatarData.kt | 8 ++++++ .../overview/CreateAccountOverviewParams.kt | 3 ++- .../CreatePersonalAccountOverviewScreen.kt | 10 ++++++-- .../ui/authentication/devices/DeviceItem.kt | 12 ++++++++- .../android/ui/common/UserProfileAvatar.kt | 15 +++++++++-- .../wire/android/ui/common/WireDropDown.kt | 21 +++++++++++----- .../ConversationParticipantItem.kt | 14 +++++++++-- .../search/HighLightSubtTitle.kt | 6 ++++- .../search/SearchUsersAndServicesScreen.kt | 7 ++++-- .../common/ConversationItemFactory.kt | 25 +++++++++++++------ .../ui/home/messagecomposer/MessageActions.kt | 2 +- .../recordaudio/RecordAudioButtons.kt | 2 +- .../self/dialog/LogoutOptionsDialog.kt | 3 ++- app/src/main/res/values/strings.xml | 5 ++++ .../com/wire/android/ui/common/WireDialog.kt | 12 +++++---- .../bottomsheet/ModalSheetHeaderItem.kt | 4 +-- .../android/ui/common/button/WireButton.kt | 16 +++++++++--- .../android/ui/common/button/WireItemLabel.kt | 6 +++-- .../ui/common/button/WirePrimaryButton.kt | 6 +++-- .../ui/common/button/WireSecondaryButton.kt | 6 +++-- .../ui/common/button/WireTertiaryButton.kt | 6 +++-- .../common/topappbar/NavigationIconButton.kt | 4 +-- .../ui-common/src/main/res/values/strings.xml | 2 ++ 23 files changed, 146 insertions(+), 49 deletions(-) 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..634b57c5e75 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,12 @@ 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 this.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..76e88c49a66 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,21 @@ private fun ColumnScope.DeviceItemTexts( .fillMaxWidth() .shimmerPlaceholder(visible = placeholder) ) { + val deviceName = device.name.asString() + val semantic = if (shouldShowVerifyLabel && !shouldShowE2EIInfo && !(device.isVerifiedProteus && !isCurrentClient)) { + 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) { 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/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/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/common/ConversationItemFactory.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/common/ConversationItemFactory.kt index 44ac89e3f7a..44f9ec4c763 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 acceptOrIgnoreConnectionDescription = 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) { + acceptOrIgnoreConnectionDescription + } 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/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/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 From 385b46b438d7e5ad4d57a081ee2b390b5f970dbc Mon Sep 17 00:00:00 2001 From: Boris Safonov Date: Fri, 22 Nov 2024 15:48:21 +0200 Subject: [PATCH 2/2] Fixed code style --- .../CreatePersonalAccountOverviewScreen.kt | 7 +++++-- .../ui/authentication/devices/DeviceItem.kt | 19 ++++++++++++++++++- .../common/ConversationItemFactory.kt | 4 ++-- 3 files changed, 25 insertions(+), 5 deletions(-) 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 634b57c5e75..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 @@ -197,8 +197,11 @@ private fun OverviewTexts( modifier = Modifier .fillMaxWidth() .run { - if (overviewParams.isContentTextSemanticAccessible) this - else this.clearAndSetSemantics {} + if (overviewParams.isContentTextSemanticAccessible) { + this + } else { + clearAndSetSemantics {} + } } ) Text( 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 76e88c49a66..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 @@ -192,7 +192,8 @@ private fun ColumnScope.DeviceItemTexts( .shimmerPlaceholder(visible = placeholder) ) { val deviceName = device.name.asString() - val semantic = if (shouldShowVerifyLabel && !shouldShowE2EIInfo && !(device.isVerifiedProteus && !isCurrentClient)) { + 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 { @@ -233,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, @@ -248,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/home/conversationslist/common/ConversationItemFactory.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversationslist/common/ConversationItemFactory.kt index 44f9ec4c763..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 @@ -76,13 +76,13 @@ 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 acceptOrIgnoreConnectionDescription = stringResource(R.string.content_description_accept_or_ignore_connection_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 -> { val onClickDescription = if (conversation.badgeEventType == BadgeEventType.ReceivedConnectionRequest) { - acceptOrIgnoreConnectionDescription + acceptOrIgnoreDescription } else { openUserProfileDescription }