diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index 8217cb977cd..e20526d0830 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -36,7 +36,6 @@ import io.element.android.features.messages.impl.timeline.protection.TimelinePro import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState import io.element.android.features.roomcall.api.RoomCallState import io.element.android.features.roomcall.api.aStandByCallState -import io.element.android.features.roomcall.api.anOngoingCallState import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents import io.element.android.features.roommembermoderation.api.RoomMemberModerationState import io.element.android.libraries.architecture.AsyncData @@ -60,36 +59,29 @@ open class MessagesStateProvider : PreviewParameterProvider { aMessagesState(composerState = aMessageComposerState(showAttachmentSourcePicker = true)), aMessagesState(userEventPermissions = aUserEventPermissions(canSendMessage = false)), aMessagesState(showReinvitePrompt = true), - aMessagesState(roomName = null), aMessagesState(composerState = aMessageComposerState(showTextFormatting = true)), aMessagesState( voiceMessageComposerState = aVoiceMessageComposerState(showPermissionRationaleDialog = true), ), - aMessagesState( - roomCallState = anOngoingCallState(), - ), aMessagesState( voiceMessageComposerState = aVoiceMessageComposerState( voiceMessageState = aVoiceMessagePreviewState(), showSendFailureDialog = true ), ), - aMessagesState( - roomCallState = aStandByCallState(canStartCall = false), - ), aMessagesState( pinnedMessagesBannerState = aLoadedPinnedMessagesBannerState( knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 0, ), ), - aMessagesState(roomName = "A DM with a very looong name", dmUserVerificationState = IdentityState.Verified), - aMessagesState(roomName = "A DM with a very looong name", dmUserVerificationState = IdentityState.VerificationViolation), aMessagesState(successorRoom = SuccessorRoom(RoomId("!id:domain"), null)), - aMessagesState(timelineState = aTimelineState( - timelineMode = Timeline.Mode.Thread(threadRootId = ThreadId("\$a-thread-id")), - timelineItems = aTimelineItemList(aTimelineItemTextContent()), - )), + aMessagesState( + timelineState = aTimelineState( + timelineMode = Timeline.Mode.Thread(threadRootId = ThreadId("\$a-thread-id")), + timelineItems = aTimelineItemList(aTimelineItemTextContent()), + ) + ), ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 1cc84eee786..07fc1787217 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -11,12 +11,10 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize @@ -27,30 +25,23 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.systemBarsPadding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role -import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme -import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.messages.api.timeline.voicemessages.composer.VoiceMessageComposerEvents import io.element.android.features.messages.impl.actionlist.ActionListEvents import io.element.android.features.messages.impl.actionlist.ActionListView @@ -69,7 +60,6 @@ import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBan import io.element.android.features.messages.impl.timeline.FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineView -import io.element.android.features.messages.impl.timeline.components.CallMenuItem import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionBottomSheet import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionEvents import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryEvents @@ -77,30 +67,23 @@ import io.element.android.features.messages.impl.timeline.components.reactionsum import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheet import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetEvents import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.topbars.MessagesViewTopBar +import io.element.android.features.messages.impl.topbars.ThreadTopBar import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessagePermissionRationaleDialog import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageSendingFailedDialog import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView -import io.element.android.features.roomcall.api.RoomCallState import io.element.android.libraries.androidutils.ui.hideKeyboard import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule import io.element.android.libraries.designsystem.components.ExpandableBottomSheetLayout import io.element.android.libraries.designsystem.components.ExpandableBottomSheetLayoutState -import io.element.android.libraries.designsystem.components.avatar.Avatar -import io.element.android.libraries.designsystem.components.avatar.AvatarData -import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.designsystem.components.avatar.AvatarType -import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.components.rememberExpandableBottomSheetLayoutState import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.text.toAnnotatedString import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle -import io.element.android.libraries.designsystem.theme.components.HorizontalDivider -import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.utils.HideKeyboardWhenDisposed import io.element.android.libraries.designsystem.utils.KeepScreenOn import io.element.android.libraries.designsystem.utils.OnLifecycleEvent @@ -113,14 +96,9 @@ import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.components.aMatrixUserList -import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.textcomposer.model.TextEditorState import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.wysiwyg.link.Link -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList import timber.log.Timber import kotlin.time.Duration.Companion.milliseconds @@ -517,154 +495,6 @@ private fun MessagesViewComposerBottomSheetContents( } } -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun MessagesViewTopBar( - roomName: String?, - roomAvatar: AvatarData, - isTombstoned: Boolean, - heroes: ImmutableList, - roomCallState: RoomCallState, - dmUserIdentityState: IdentityState?, - onRoomDetailsClick: () -> Unit, - onJoinCallClick: () -> Unit, - onBackClick: () -> Unit, -) { - TopAppBar( - navigationIcon = { - BackButton(onClick = onBackClick) - }, - title = { - val roundedCornerShape = RoundedCornerShape(8.dp) - Row( - modifier = Modifier - .clip(roundedCornerShape) - .clickable { onRoomDetailsClick() }, - horizontalArrangement = Arrangement.spacedBy(4.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - val titleModifier = Modifier.weight(1f, fill = false) - RoomAvatarAndNameRow( - roomName = roomName, - roomAvatar = roomAvatar, - isTombstoned = isTombstoned, - heroes = heroes, - modifier = titleModifier - ) - - when (dmUserIdentityState) { - IdentityState.Verified -> { - Icon( - imageVector = CompoundIcons.Verified(), - tint = ElementTheme.colors.iconSuccessPrimary, - contentDescription = null, - ) - } - IdentityState.VerificationViolation -> { - Icon( - imageVector = CompoundIcons.ErrorSolid(), - tint = ElementTheme.colors.iconCriticalPrimary, - contentDescription = null, - ) - } - else -> Unit - } - } - }, - actions = { - CallMenuItem( - roomCallState = roomCallState, - onJoinCallClick = onJoinCallClick, - ) - Spacer(Modifier.width(8.dp)) - }, - windowInsets = WindowInsets(0.dp) - ) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun ThreadTopBar( - roomName: String?, - roomAvatarData: AvatarData, - heroes: ImmutableList, - isTombstoned: Boolean, - onBackClick: () -> Unit, - modifier: Modifier = Modifier, -) { - TopAppBar( - modifier = modifier, - navigationIcon = { - BackButton(onClick = onBackClick) - }, - title = { - Row(verticalAlignment = Alignment.CenterVertically) { - Avatar( - avatarData = roomAvatarData, - avatarType = AvatarType.Room( - heroes = heroes, - isTombstoned = isTombstoned, - ), - ) - Column( - modifier = Modifier.fillMaxWidth() - .padding(horizontal = 8.dp) - .semantics { - heading() - }, - ) { - Text( - text = stringResource(CommonStrings.common_thread), - style = ElementTheme.typography.fontBodyLgMedium, - ) - Text( - text = roomName ?: stringResource(CommonStrings.common_no_room_name), - style = ElementTheme.typography.fontBodySmRegular, - fontStyle = FontStyle.Italic.takeIf { roomName == null }, - color = ElementTheme.colors.textSecondary, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - } - ) -} - -@Composable -private fun RoomAvatarAndNameRow( - roomName: String?, - roomAvatar: AvatarData, - heroes: ImmutableList, - isTombstoned: Boolean, - modifier: Modifier = Modifier -) { - Row( - modifier = modifier, - verticalAlignment = Alignment.CenterVertically - ) { - Avatar( - avatarData = roomAvatar, - avatarType = AvatarType.Room( - heroes = heroes, - isTombstoned = isTombstoned, - ), - ) - Text( - modifier = Modifier - .padding(horizontal = 8.dp) - .semantics { - heading() - }, - text = roomName ?: stringResource(CommonStrings.common_no_room_name), - style = ElementTheme.typography.fontBodyLgMedium, - fontStyle = FontStyle.Italic.takeIf { roomName == null }, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } -} - @Composable private fun CantSendMessageBanner() { Row( @@ -719,58 +549,3 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class) knockRequestsBannerView = {}, ) } - -@PreviewsDayNight -@Composable -internal fun ThreadTopBarPreview() { - ElementPreview { - val name = "Room name" - val initialsAvatarData = AvatarData( - id = "id", - name = name, - url = null, - size = AvatarSize.TimelineRoom, - ) - Column { - ThreadTopBar( - roomName = name, - roomAvatarData = initialsAvatarData, - heroes = persistentListOf(), - isTombstoned = false, - onBackClick = {}, - ) - HorizontalDivider() - ThreadTopBar( - roomName = name, - roomAvatarData = initialsAvatarData, - heroes = aMatrixUserList().map { it.getAvatarData(AvatarSize.TimelineRoom) }.toImmutableList(), - isTombstoned = false, - onBackClick = {}, - ) - HorizontalDivider() - ThreadTopBar( - roomName = null, - roomAvatarData = initialsAvatarData, - heroes = persistentListOf(), - isTombstoned = false, - onBackClick = {}, - ) - HorizontalDivider() - ThreadTopBar( - roomName = name, - roomAvatarData = initialsAvatarData.copy(url = "https://some-avatar.jpg"), - heroes = persistentListOf(), - isTombstoned = false, - onBackClick = {}, - ) - HorizontalDivider() - ThreadTopBar( - roomName = name, - roomAvatarData = initialsAvatarData, - heroes = persistentListOf(), - isTombstoned = true, - onBackClick = {}, - ) - } - } -} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/MessagesViewTopBar.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/MessagesViewTopBar.kt new file mode 100644 index 00000000000..62c9c3e2064 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/MessagesViewTopBar.kt @@ -0,0 +1,211 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.topbars + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.heading +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.features.messages.impl.timeline.components.CallMenuItem +import io.element.android.features.roomcall.api.RoomCallState +import io.element.android.features.roomcall.api.aStandByCallState +import io.element.android.features.roomcall.api.anOngoingCallState +import io.element.android.libraries.designsystem.components.avatar.Avatar +import io.element.android.libraries.designsystem.components.avatar.AvatarData +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.components.avatar.AvatarType +import io.element.android.libraries.designsystem.components.avatar.anAvatarData +import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.matrix.api.encryption.identity.IdentityState +import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import io.element.android.libraries.matrix.ui.model.getAvatarData +import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun MessagesViewTopBar( + roomName: String?, + roomAvatar: AvatarData, + isTombstoned: Boolean, + heroes: ImmutableList, + roomCallState: RoomCallState, + dmUserIdentityState: IdentityState?, + onRoomDetailsClick: () -> Unit, + onJoinCallClick: () -> Unit, + onBackClick: () -> Unit, + modifier: Modifier = Modifier, +) { + TopAppBar( + modifier = modifier, + navigationIcon = { + BackButton(onClick = onBackClick) + }, + title = { + val roundedCornerShape = RoundedCornerShape(8.dp) + Row( + modifier = Modifier + .clip(roundedCornerShape) + .clickable { onRoomDetailsClick() }, + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + val titleModifier = Modifier.weight(1f, fill = false) + RoomAvatarAndNameRow( + roomName = roomName, + roomAvatar = roomAvatar, + isTombstoned = isTombstoned, + heroes = heroes, + modifier = titleModifier + ) + + when (dmUserIdentityState) { + IdentityState.Verified -> { + Icon( + imageVector = CompoundIcons.Verified(), + tint = ElementTheme.colors.iconSuccessPrimary, + contentDescription = null, + ) + } + IdentityState.VerificationViolation -> { + Icon( + imageVector = CompoundIcons.ErrorSolid(), + tint = ElementTheme.colors.iconCriticalPrimary, + contentDescription = null, + ) + } + else -> Unit + } + } + }, + actions = { + CallMenuItem( + roomCallState = roomCallState, + onJoinCallClick = onJoinCallClick, + ) + Spacer(Modifier.width(8.dp)) + }, + windowInsets = WindowInsets(0.dp) + ) +} + +@Composable +private fun RoomAvatarAndNameRow( + roomName: String?, + roomAvatar: AvatarData, + heroes: ImmutableList, + isTombstoned: Boolean, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically + ) { + Avatar( + avatarData = roomAvatar, + avatarType = AvatarType.Room( + heroes = heroes, + isTombstoned = isTombstoned, + ), + ) + Text( + modifier = Modifier + .padding(horizontal = 8.dp) + .semantics { + heading() + }, + text = roomName ?: stringResource(CommonStrings.common_no_room_name), + style = ElementTheme.typography.fontBodyLgMedium, + fontStyle = FontStyle.Italic.takeIf { roomName == null }, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } +} + +@PreviewsDayNight +@Composable +internal fun MessagesViewTopBarPreview() = ElementPreview { + @Composable + fun AMessagesViewTopBar( + roomName: String? = "Room name", + roomAvatar: AvatarData = anAvatarData( + name = "Room name", + size = AvatarSize.TimelineRoom, + ), + isTombstoned: Boolean = false, + heroes: ImmutableList = persistentListOf(), + roomCallState: RoomCallState = RoomCallState.Unavailable, + dmUserIdentityState: IdentityState? = null, + ) = MessagesViewTopBar( + roomName = roomName, + roomAvatar = roomAvatar, + isTombstoned = isTombstoned, + heroes = heroes, + roomCallState = roomCallState, + dmUserIdentityState = dmUserIdentityState, + onRoomDetailsClick = {}, + onJoinCallClick = {}, + onBackClick = {}, + ) + Column { + AMessagesViewTopBar() + HorizontalDivider() + AMessagesViewTopBar( + heroes = aMatrixUserList().map { it.getAvatarData(AvatarSize.TimelineRoom) }.toImmutableList(), + roomCallState = anOngoingCallState(), + ) + HorizontalDivider() + AMessagesViewTopBar( + roomName = null, + roomCallState = anOngoingCallState(canJoinCall = false), + ) + HorizontalDivider() + AMessagesViewTopBar( + roomName = "A DM with a very very very long name", + roomAvatar = anAvatarData( + size = AvatarSize.TimelineRoom, + url = "https://some-avatar.jpg" + ), + roomCallState = aStandByCallState(canStartCall = false), + dmUserIdentityState = IdentityState.Verified + ) + HorizontalDivider() + AMessagesViewTopBar( + roomName = "A DM with a very very very long name", + isTombstoned = true, + dmUserIdentityState = IdentityState.VerificationViolation + ) + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/ThreadTopBar.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/ThreadTopBar.kt new file mode 100644 index 00000000000..5a95c2c4b29 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/ThreadTopBar.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.topbars + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +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.heading +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.designsystem.components.avatar.Avatar +import io.element.android.libraries.designsystem.components.avatar.AvatarData +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.components.avatar.AvatarType +import io.element.android.libraries.designsystem.components.avatar.anAvatarData +import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import io.element.android.libraries.matrix.ui.model.getAvatarData +import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun ThreadTopBar( + roomName: String?, + roomAvatarData: AvatarData, + heroes: ImmutableList, + isTombstoned: Boolean, + onBackClick: () -> Unit, + modifier: Modifier = Modifier, +) { + TopAppBar( + modifier = modifier, + navigationIcon = { + BackButton(onClick = onBackClick) + }, + title = { + Row(verticalAlignment = Alignment.CenterVertically) { + Avatar( + avatarData = roomAvatarData, + avatarType = AvatarType.Room( + heroes = heroes, + isTombstoned = isTombstoned, + ), + ) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp) + .semantics { + heading() + }, + ) { + Text( + text = stringResource(CommonStrings.common_thread), + style = ElementTheme.typography.fontBodyLgMedium, + ) + Text( + text = roomName ?: stringResource(CommonStrings.common_no_room_name), + style = ElementTheme.typography.fontBodySmRegular, + fontStyle = FontStyle.Italic.takeIf { roomName == null }, + color = ElementTheme.colors.textSecondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + } + ) +} + +@PreviewsDayNight +@Composable +internal fun ThreadTopBarPreview() = ElementPreview { + @Composable + fun AThreadTopBar( + roomName: String? = "Room name", + roomAvatarData: AvatarData = anAvatarData( + name = "Room name", + size = AvatarSize.TimelineRoom, + ), + isTombstoned: Boolean = false, + heroes: ImmutableList = persistentListOf(), + ) = ThreadTopBar( + roomName = roomName, + roomAvatarData = roomAvatarData, + isTombstoned = isTombstoned, + heroes = heroes, + onBackClick = {}, + ) + Column { + AThreadTopBar() + HorizontalDivider() + AThreadTopBar( + heroes = aMatrixUserList().map { it.getAvatarData(AvatarSize.TimelineRoom) }.toImmutableList(), + ) + HorizontalDivider() + AThreadTopBar( + roomName = null, + ) + HorizontalDivider() + AThreadTopBar( + roomAvatarData = anAvatarData( + name = "Room name", + url = "https://some-avatar.jpg", + size = AvatarSize.TimelineRoom, + ), + ) + HorizontalDivider() + AThreadTopBar( + isTombstoned = true, + ) + } +} diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png new file mode 100644 index 00000000000..571661e4348 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:065466dc414d77a58f2d22c26fc9d5e9b7afe5d5206cdbcc2bbdc6e8ea192d15 +size 40479 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png new file mode 100644 index 00000000000..958d12766d7 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c34b8c47d89231b8e5660726d63b94e3e8b97a2fc7e0b615f8f9e2d61066470 +size 39172 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png new file mode 100644 index 00000000000..079ac780f89 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:617a819de3cd223323b0fa1853185ceb26ffb97a22d79524acec0f4d5b3a634b +size 33550 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png new file mode 100644 index 00000000000..b3f0e9c13ed --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e146eee5e94e29a2b87b3d4a9bf248445e08dc6eb68c2268b6f263533675c78 +size 33050 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png index 94548f50d87..11b3313094e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e1ffac0c95378fa7778a4d5b3e5af5a47eef44757f13dbe0032d30b30f96561b -size 58549 +oid sha256:9571176fb73b9871b6db3c30679a46c776badb56d4e1919ea882b391d893b8c4 +size 53144 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png deleted file mode 100644 index 4ab2179c6b3..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:983db5846ee050f682b895ef0ce54362b1214c5bee48ef94139ef825e0ecbab6 -size 61678 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png deleted file mode 100644 index 788ff1abe66..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:501b8bc5c6163c85d1aaee4c9b81c56610931b6d693421d87b5107b3389170ea -size 60829 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png deleted file mode 100644 index 25a8d03e4ac..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b116183b02d89b112d35ae86d68fdfcec0cb63e5ded20c611a152836090b19b2 -size 60755 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_14_en.png deleted file mode 100644 index 22fda1dd27b..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_14_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0fd783aa6c219e5bdc3c03579bd823a286e6048581728a6786ee724ef458050c -size 63807 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_15_en.png deleted file mode 100644 index 11b3313094e..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_15_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9571176fb73b9871b6db3c30679a46c776badb56d4e1919ea882b391d893b8c4 -size 53144 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png index abd6861f7ee..657dc6d2ac6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:373b60146f1fe215eea0c559fbe9810bfe9b714f021e3dddbb649dd6105c5f43 -size 59547 +oid sha256:f6a08f9b69ec278f8706c8de459fd6d2747cef7ed51da32eb7239667d0805e58 +size 55311 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png index 657dc6d2ac6..3d2d2949ab6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6a08f9b69ec278f8706c8de459fd6d2747cef7ed51da32eb7239667d0805e58 -size 55311 +oid sha256:1b298a6432190f54fdb824c7edc2f8cda30a746d2a13322793c84a5a3d42f5ea +size 59985 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png index 3d2d2949ab6..e3b8e08ac7a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b298a6432190f54fdb824c7edc2f8cda30a746d2a13322793c84a5a3d42f5ea -size 59985 +oid sha256:61add48c03d1f4df4bc9010826c4a6f5adaa312ef5f910bc0b3a77211a377f66 +size 50651 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png index 8c8344673d0..4ab2179c6b3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:34a70e62b687f5726073a2339a4246f0e6bf31c187483829082612be69938087 -size 60107 +oid sha256:983db5846ee050f682b895ef0ce54362b1214c5bee48ef94139ef825e0ecbab6 +size 61678 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png index e3b8e08ac7a..22fda1dd27b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61add48c03d1f4df4bc9010826c4a6f5adaa312ef5f910bc0b3a77211a377f66 -size 50651 +oid sha256:0fd783aa6c219e5bdc3c03579bd823a286e6048581728a6786ee724ef458050c +size 63807 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png index 68918896b21..7d33111f68d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:edc830108c2dd54d594a383020c2e73dba6b6fdff44e279b87889f3dc84ea546 -size 56308 +oid sha256:d6ea6d7eb98c546dbee109d160e2adbbbd4d22d4844835667bfbab1de2060115 +size 52351 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png deleted file mode 100644 index 0ef6da37c96..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bf12305ee99f199905e94e325743b1589f11d36815e16e86558691400e2991e3 -size 59022 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png deleted file mode 100644 index 98512acaa5c..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e1b50937116f9d14103a1753199686f959371b8fe6ad006cadf1c3fb121fb72a -size 58491 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png deleted file mode 100644 index 9ed77630726..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8f5c6283d080341dd600f723329355447fa190c8b36aa4241536c4993ce55b76 -size 58466 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_14_en.png deleted file mode 100644 index 998c5ab138a..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_14_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:01ea3893df495012f2e417e81d2223696ee11efe2499c0c2a112f015c1f72f7a -size 64610 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_15_en.png deleted file mode 100644 index 7d33111f68d..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_15_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d6ea6d7eb98c546dbee109d160e2adbbbd4d22d4844835667bfbab1de2060115 -size 52351 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png index 06f314231c6..c041fd7d110 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21ef350495865cd55510b9dd59ffcb7fa3600369df3077322c352e47cc8d93b1 -size 57291 +oid sha256:c1534b9c3b6952c290ca20a2853e56be023e5c8129a10b9f3fd63c290c7ba9fb +size 52977 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png index c041fd7d110..7a6efabb582 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1534b9c3b6952c290ca20a2853e56be023e5c8129a10b9f3fd63c290c7ba9fb -size 52977 +oid sha256:7b50e874595cfcb65cf2a4f7146ed7c99ee06899d6512024b900a64439748a6f +size 54078 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png index 7a6efabb582..21888106d23 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b50e874595cfcb65cf2a4f7146ed7c99ee06899d6512024b900a64439748a6f -size 54078 +oid sha256:aafdc477f090674d0473076071049bba77bc57025c602cb6bc1cdfada03a1937 +size 44740 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png index 2745c0ff609..0ef6da37c96 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5052598f1d095bb854522a2b0e880a6a88c070e372e1a2fd73b487611f8f733 -size 57716 +oid sha256:bf12305ee99f199905e94e325743b1589f11d36815e16e86558691400e2991e3 +size 59022 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png index 21888106d23..998c5ab138a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aafdc477f090674d0473076071049bba77bc57025c602cb6bc1cdfada03a1937 -size 44740 +oid sha256:01ea3893df495012f2e417e81d2223696ee11efe2499c0c2a112f015c1f72f7a +size 64610 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_ThreadTopBar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_ThreadTopBar_Day_0_en.png deleted file mode 100644 index 29d2a7fee42..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_ThreadTopBar_Day_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:10ef1d5b008da94cdf48525d98bdb1e10f6013124c499f67c9fcd39bee85b7aa -size 33773 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_ThreadTopBar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_ThreadTopBar_Night_0_en.png deleted file mode 100644 index 6a5b2313059..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_ThreadTopBar_Night_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d98bfa7c506d089ae16b2f35ffa4e189ae1a31ca114333d755fd837b13128759 -size 32921