Merge pull request #5401 from element-hq/feature/bma/messagesViewTopBars

Rework on messages view top bars
This commit is contained in:
Benoit Marty 2025-09-24 14:15:22 +02:00 committed by GitHub
commit a953547837
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 390 additions and 301 deletions

View file

@ -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<MessagesState> {
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()),
)
),
)
}

View file

@ -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<AvatarData>,
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<AvatarData>,
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<AvatarData>,
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 = {},
)
}
}
}

View file

@ -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<AvatarData>,
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<AvatarData>,
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<AvatarData> = 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
)
}
}

View file

@ -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<AvatarData>,
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<AvatarData> = 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,
)
}
}

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:065466dc414d77a58f2d22c26fc9d5e9b7afe5d5206cdbcc2bbdc6e8ea192d15
size 40479

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c34b8c47d89231b8e5660726d63b94e3e8b97a2fc7e0b615f8f9e2d61066470
size 39172

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:617a819de3cd223323b0fa1853185ceb26ffb97a22d79524acec0f4d5b3a634b
size 33550

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6e146eee5e94e29a2b87b3d4a9bf248445e08dc6eb68c2268b6f263533675c78
size 33050

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e1ffac0c95378fa7778a4d5b3e5af5a47eef44757f13dbe0032d30b30f96561b
size 58549
oid sha256:9571176fb73b9871b6db3c30679a46c776badb56d4e1919ea882b391d893b8c4
size 53144

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:983db5846ee050f682b895ef0ce54362b1214c5bee48ef94139ef825e0ecbab6
size 61678

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:501b8bc5c6163c85d1aaee4c9b81c56610931b6d693421d87b5107b3389170ea
size 60829

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b116183b02d89b112d35ae86d68fdfcec0cb63e5ded20c611a152836090b19b2
size 60755

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0fd783aa6c219e5bdc3c03579bd823a286e6048581728a6786ee724ef458050c
size 63807

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9571176fb73b9871b6db3c30679a46c776badb56d4e1919ea882b391d893b8c4
size 53144

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:373b60146f1fe215eea0c559fbe9810bfe9b714f021e3dddbb649dd6105c5f43
size 59547
oid sha256:f6a08f9b69ec278f8706c8de459fd6d2747cef7ed51da32eb7239667d0805e58
size 55311

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f6a08f9b69ec278f8706c8de459fd6d2747cef7ed51da32eb7239667d0805e58
size 55311
oid sha256:1b298a6432190f54fdb824c7edc2f8cda30a746d2a13322793c84a5a3d42f5ea
size 59985

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b298a6432190f54fdb824c7edc2f8cda30a746d2a13322793c84a5a3d42f5ea
size 59985
oid sha256:61add48c03d1f4df4bc9010826c4a6f5adaa312ef5f910bc0b3a77211a377f66
size 50651

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:34a70e62b687f5726073a2339a4246f0e6bf31c187483829082612be69938087
size 60107
oid sha256:983db5846ee050f682b895ef0ce54362b1214c5bee48ef94139ef825e0ecbab6
size 61678

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:61add48c03d1f4df4bc9010826c4a6f5adaa312ef5f910bc0b3a77211a377f66
size 50651
oid sha256:0fd783aa6c219e5bdc3c03579bd823a286e6048581728a6786ee724ef458050c
size 63807

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:edc830108c2dd54d594a383020c2e73dba6b6fdff44e279b87889f3dc84ea546
size 56308
oid sha256:d6ea6d7eb98c546dbee109d160e2adbbbd4d22d4844835667bfbab1de2060115
size 52351

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bf12305ee99f199905e94e325743b1589f11d36815e16e86558691400e2991e3
size 59022

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e1b50937116f9d14103a1753199686f959371b8fe6ad006cadf1c3fb121fb72a
size 58491

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8f5c6283d080341dd600f723329355447fa190c8b36aa4241536c4993ce55b76
size 58466

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:01ea3893df495012f2e417e81d2223696ee11efe2499c0c2a112f015c1f72f7a
size 64610

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d6ea6d7eb98c546dbee109d160e2adbbbd4d22d4844835667bfbab1de2060115
size 52351

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21ef350495865cd55510b9dd59ffcb7fa3600369df3077322c352e47cc8d93b1
size 57291
oid sha256:c1534b9c3b6952c290ca20a2853e56be023e5c8129a10b9f3fd63c290c7ba9fb
size 52977

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c1534b9c3b6952c290ca20a2853e56be023e5c8129a10b9f3fd63c290c7ba9fb
size 52977
oid sha256:7b50e874595cfcb65cf2a4f7146ed7c99ee06899d6512024b900a64439748a6f
size 54078

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7b50e874595cfcb65cf2a4f7146ed7c99ee06899d6512024b900a64439748a6f
size 54078
oid sha256:aafdc477f090674d0473076071049bba77bc57025c602cb6bc1cdfada03a1937
size 44740

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b5052598f1d095bb854522a2b0e880a6a88c070e372e1a2fd73b487611f8f733
size 57716
oid sha256:bf12305ee99f199905e94e325743b1589f11d36815e16e86558691400e2991e3
size 59022

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:aafdc477f090674d0473076071049bba77bc57025c602cb6bc1cdfada03a1937
size 44740
oid sha256:01ea3893df495012f2e417e81d2223696ee11efe2499c0c2a112f015c1f72f7a
size 64610

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:10ef1d5b008da94cdf48525d98bdb1e10f6013124c499f67c9fcd39bee85b7aa
size 33773

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d98bfa7c506d089ae16b2f35ffa4e189ae1a31ca114333d755fd837b13128759
size 32921