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/WireDropDown.kt b/app/src/main/kotlin/com/wire/android/ui/common/WireDropDown.kt index b2da6fc4d46..0ea54cc114c 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 @@ -168,6 +169,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, @@ -182,6 +185,7 @@ 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( @@ -191,7 +195,7 @@ private fun MenuPopUp( arrowRotation = arrowRotation, modifier = Modifier.clickable(onClickLabel = stringResource(R.string.content_description_close_dropdown)) { hidePopUp() - }, + } ) List(items.size) { index -> @@ -268,6 +272,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( @@ -287,8 +292,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/common/avatar/UserProfileAvatar.kt b/app/src/main/kotlin/com/wire/android/ui/common/avatar/UserProfileAvatar.kt index e26a223f4dd..86581480232 100644 --- a/app/src/main/kotlin/com/wire/android/ui/common/avatar/UserProfileAvatar.kt +++ b/app/src/main/kotlin/com/wire/android/ui/common/avatar/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 @@ -291,12 +294,19 @@ private fun DefaultInitialsAvatar( type: UserProfileAvatarType, size: Dp, modifier: Modifier = Modifier, - contentDescription: String? = stringResource(R.string.content_description_user_avatar), + contentDescription: String? = null, ) { + 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( @@ -312,6 +322,7 @@ private fun DefaultInitialsAvatar( ) } ) + .then(semantics) ) { Text( text = nameBasedAvatar.initials, 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 6f865c57870..317f56dbe2a 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 1ace87650f4..35c8a79c809 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 @@ -51,7 +51,7 @@ fun HighlightSubtitle( if (searchQuery != String.EMPTY && highlightIndexes.isNotEmpty()) { Text( - buildAnnotatedString { + text = buildAnnotatedString { withStyle( style = SpanStyle( color = MaterialTheme.wireColorScheme.secondaryText, 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 e7311dbe4ed..45db07413b1 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/userprofile/self/dialog/LogoutOptionsDialog.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/dialog/LogoutOptionsDialog.kt index 3992ff11ece..19e2fd9b6cc 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 @@ -54,7 +54,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 826347c0d64..36c6d043c92 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 @@ -624,6 +628,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 abda14ccdc2..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 @@ -48,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 @@ -89,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) @@ -122,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, @@ -142,6 +148,7 @@ fun WireButton( textStyle = textStyle, state = state, colors = colors, + semanticIgnoreText = !description.isNullOrEmpty() ) } } @@ -159,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) } } @@ -196,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