Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Accessibility strings founded issues #WPB-9784 #3657

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/src/main/kotlin/com/wire/android/model/UserAvatarData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
)
}
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -266,6 +276,7 @@ private fun DefaultInitialsAvatar(
)
}
)
.then(semantics)
) {
Text(
text = nameBasedAvatar.initials,
Expand Down
21 changes: 15 additions & 6 deletions app/src/main/kotlin/com/wire/android/ui/common/WireDropDown.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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 ->
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,6 +34,7 @@ import com.wire.android.util.QueryMatchExtractor
@Composable
fun HighlightSubtitle(
subTitle: String,
modifier: Modifier = Modifier,
searchQuery: String = String.EMPTY,
prefix: String = "@"
) {
Expand Down Expand Up @@ -76,6 +78,7 @@ fun HighlightSubtitle(
}
}
},
modifier = modifier,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Expand All @@ -85,7 +88,8 @@ fun HighlightSubtitle(
style = MaterialTheme.wireTypography.subline01,
color = MaterialTheme.wireColorScheme.secondaryText,
maxLines = 1,
overflow = TextOverflow.Ellipsis
overflow = TextOverflow.Ellipsis,
modifier = modifier
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -97,7 +106,7 @@ fun ConversationItemFactory(
}

GeneralConversationItem(
modifier = modifier,
modifier = modifier.semantics(mergeDescendants = true) { },
conversation = conversation,
isSelectable = isSelectableItem,
isChecked = isChecked,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() } } },
Expand Down
Loading
Loading