diff --git a/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallScreen.kt b/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallScreen.kt index 8b75901595..776d301910 100644 --- a/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallScreen.kt @@ -65,6 +65,9 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.onClick +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -233,14 +236,15 @@ fun OngoingCallScreen( } BackHandler { - when { - scaffoldState.bottomSheetState.currentValue == SheetValue.Expanded -> scope.launch { - scaffoldState.bottomSheetState.partialExpand() - } - ongoingCallViewModel.state.selectedParticipant != null -> ongoingCallViewModel.onSelectedParticipant(null) - shouldUsePiPMode -> (activity as OngoingCallActivity).enterPiPMode(conversationId, ongoingCallViewModel.currentUserId) - else -> activity.moveTaskToBack(true) + when { + scaffoldState.bottomSheetState.currentValue == SheetValue.Expanded -> scope.launch { + scaffoldState.bottomSheetState.partialExpand() } + + ongoingCallViewModel.state.selectedParticipant != null -> ongoingCallViewModel.onSelectedParticipant(null) + shouldUsePiPMode -> (activity as OngoingCallActivity).enterPiPMode(conversationId, ongoingCallViewModel.currentUserId) + else -> activity.moveTaskToBack(true) + } } OngoingCallContent( @@ -437,7 +441,21 @@ private fun OngoingCallContent( } }, sheetDragHandle = { - WireDragHandle(progress = if (scaffoldState.bottomSheetState.targetValue == SheetValue.Expanded) 0f else 1f) + val dragHandleContentDescription = when (scaffoldState.bottomSheetState.targetValue) { + SheetValue.Expanded -> stringResource(id = R.string.content_description_calling_expanded_participants_list) + else -> stringResource(id = R.string.content_description_calling_collapsed_participants_list) + } + val dragHandleClickContentDescription = when (scaffoldState.bottomSheetState.targetValue) { + SheetValue.Expanded -> stringResource(id = R.string.content_description_calling_collapse) + else -> stringResource(id = R.string.content_description_calling_expand) + } + WireDragHandle( + progress = if (scaffoldState.bottomSheetState.targetValue == SheetValue.Expanded) 0f else 1f, + modifier = Modifier.semantics { + this.contentDescription = dragHandleContentDescription + this.onClick(label = dragHandleClickContentDescription, action = null) + } + ) }, sheetPeekHeight = with(LocalDensity.current) { sheetPeekHeight.toDp() }, scaffoldState = scaffoldState, @@ -497,7 +515,7 @@ private fun OngoingCallContent( } ParticipantList( lazyListState = lazyListState, - participants = participants, + participants = participants.sortedBy { it.name }.toPersistentList(), ) } } diff --git a/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/participantslist/ParticipantItem.kt b/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/participantslist/ParticipantItem.kt index 666d0a095d..a136696428 100644 --- a/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/participantslist/ParticipantItem.kt +++ b/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/participantslist/ParticipantItem.kt @@ -26,10 +26,12 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -46,6 +48,8 @@ import com.wire.android.ui.common.rowitem.RowItemTemplate import com.wire.android.ui.common.typography import com.wire.android.ui.home.conversationslist.model.Membership import com.wire.android.ui.theme.WireTheme +import com.wire.android.ui.theme.wireColorScheme +import com.wire.android.ui.theme.wireTypography import com.wire.android.util.ui.PreviewMultipleThemes @Composable @@ -56,7 +60,11 @@ fun ParticipantItem( RowItemTemplate( leadingIcon = { UserProfileAvatar( - UserAvatarData(asset = participant.avatar, nameBasedAvatar = NameBasedAvatar(participant.name, participant.accentId)), + avatarData = UserAvatarData( + asset = participant.avatar, + nameBasedAvatar = NameBasedAvatar(participant.name, participant.accentId) + ), + modifier = Modifier.alpha(if (participant.hasEstablishedAudio) 1f else 0.5f) ) }, titleStartPadding = dimensions().spacing0x, @@ -68,48 +76,77 @@ fun ParticipantItem( Text( text = participant.name.orEmpty(), style = typography().title02, - color = colorsScheme().onSurface, + color = when (participant.hasEstablishedAudio) { + true -> colorsScheme().onSurface + false -> colorsScheme().secondaryText + }, maxLines = 1, overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(weight = 1f, fill = false) ) + if (participant.isSelfUser) { + Text( + text = stringResource(R.string.conversation_participant_you_label), + style = MaterialTheme.wireTypography.title02, + color = MaterialTheme.wireColorScheme.secondaryText, + ) + } MembershipQualifierLabel(membership = participant.membership) } }, actions = { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dimensions().spacing8x) - ) { - if (participant.isSharingScreen) { - ActionIcon( - icon = R.drawable.ic_screen_share, - contentDescription = R.string.content_description_calling_screen_share_on, - ) - } - if (participant.isCameraOn) { - ActionIcon( - icon = R.drawable.ic_camera_on, - contentDescription = R.string.content_description_calling_camera_on, - ) - } - if (participant.isMuted) { - ActionIcon( - icon = R.drawable.ic_microphone_off, - contentDescription = R.string.content_description_calling_microphone_off, - ) - } else { - ActionIcon( - icon = R.drawable.ic_microphone_on, - contentDescription = R.string.content_description_calling_microphone_on, - active = participant.isSpeaking, - ) - } + when (participant.hasEstablishedAudio) { + true -> ConnectedActionIcons(participant) + false -> ConnectingLabel() } }, modifier = modifier.padding(start = dimensions().spacing8x), ) } +@Composable +private fun ConnectingLabel() { + Text( + color = colorsScheme().error, + style = MaterialTheme.wireTypography.label01, + text = stringResource(id = R.string.participant_tile_call_connecting_label), + maxLines = 1, + ) +} + +@Composable +private fun ConnectedActionIcons(participant: UICallParticipant) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(dimensions().spacing8x) + ) { + if (participant.isSharingScreen) { + ActionIcon( + icon = R.drawable.ic_screen_share, + contentDescription = R.string.content_description_calling_screen_share_on, + ) + } + if (participant.isCameraOn) { + ActionIcon( + icon = R.drawable.ic_camera_on, + contentDescription = R.string.content_description_calling_camera_on, + ) + } + if (participant.isMuted) { + ActionIcon( + icon = R.drawable.ic_microphone_off, + contentDescription = R.string.content_description_calling_microphone_off, + ) + } else { + ActionIcon( + icon = R.drawable.ic_microphone_on, + contentDescription = R.string.content_description_calling_microphone_on, + active = participant.isSpeaking, + ) + } + } +} + @Composable private fun ActionIcon( @DrawableRes icon: Int, @@ -179,3 +216,15 @@ fun PreviewParticipantItem_NotMutedWithScreenShare() = WireTheme { fun PreviewParticipantItem_MutedGuest() = WireTheme { ParticipantItem(participant = previewParticipant.copy(isMuted = true, membership = Membership.Guest)) } + +@PreviewMultipleThemes +@Composable +fun PreviewParticipantItem_SelfUser() = WireTheme { + ParticipantItem(participant = previewParticipant.copy(isSelfUser = true, name = "Participant with a very long name to be truncated")) +} + +@PreviewMultipleThemes +@Composable +fun PreviewParticipantItem_Connecting() = WireTheme { + ParticipantItem(participant = previewParticipant.copy(hasEstablishedAudio = false)) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4796c02338..e785b93d19 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -165,6 +165,11 @@ Microphone on Microphone off Active speaker + Expand list of participants + Expand + Collapse + Expanded list of participants + Collapsed list of participants Show in call reactions panel Hide in call reactions panel Open calling details