Skip to content

Commit a953547

Browse files
authored
Merge pull request #5401 from element-hq/feature/bma/messagesViewTopBars
Rework on messages view top bars
2 parents 6cd0af9 + 321c5f6 commit a953547

File tree

32 files changed

+390
-301
lines changed

32 files changed

+390
-301
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import io.element.android.features.messages.impl.timeline.protection.TimelinePro
3636
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
3737
import io.element.android.features.roomcall.api.RoomCallState
3838
import io.element.android.features.roomcall.api.aStandByCallState
39-
import io.element.android.features.roomcall.api.anOngoingCallState
4039
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
4140
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
4241
import io.element.android.libraries.architecture.AsyncData
@@ -60,36 +59,29 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
6059
aMessagesState(composerState = aMessageComposerState(showAttachmentSourcePicker = true)),
6160
aMessagesState(userEventPermissions = aUserEventPermissions(canSendMessage = false)),
6261
aMessagesState(showReinvitePrompt = true),
63-
aMessagesState(roomName = null),
6462
aMessagesState(composerState = aMessageComposerState(showTextFormatting = true)),
6563
aMessagesState(
6664
voiceMessageComposerState = aVoiceMessageComposerState(showPermissionRationaleDialog = true),
6765
),
68-
aMessagesState(
69-
roomCallState = anOngoingCallState(),
70-
),
7166
aMessagesState(
7267
voiceMessageComposerState = aVoiceMessageComposerState(
7368
voiceMessageState = aVoiceMessagePreviewState(),
7469
showSendFailureDialog = true
7570
),
7671
),
77-
aMessagesState(
78-
roomCallState = aStandByCallState(canStartCall = false),
79-
),
8072
aMessagesState(
8173
pinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(
8274
knownPinnedMessagesCount = 4,
8375
currentPinnedMessageIndex = 0,
8476
),
8577
),
86-
aMessagesState(roomName = "A DM with a very looong name", dmUserVerificationState = IdentityState.Verified),
87-
aMessagesState(roomName = "A DM with a very looong name", dmUserVerificationState = IdentityState.VerificationViolation),
8878
aMessagesState(successorRoom = SuccessorRoom(RoomId("!id:domain"), null)),
89-
aMessagesState(timelineState = aTimelineState(
90-
timelineMode = Timeline.Mode.Thread(threadRootId = ThreadId("\$a-thread-id")),
91-
timelineItems = aTimelineItemList(aTimelineItemTextContent()),
92-
)),
79+
aMessagesState(
80+
timelineState = aTimelineState(
81+
timelineMode = Timeline.Mode.Thread(threadRootId = ThreadId("\$a-thread-id")),
82+
timelineItems = aTimelineItemList(aTimelineItemTextContent()),
83+
)
84+
),
9385
)
9486
}
9587

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt

Lines changed: 2 additions & 227 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@ import androidx.compose.animation.AnimatedVisibility
1111
import androidx.compose.animation.expandVertically
1212
import androidx.compose.animation.shrinkVertically
1313
import androidx.compose.foundation.background
14-
import androidx.compose.foundation.clickable
1514
import androidx.compose.foundation.layout.Arrangement
1615
import androidx.compose.foundation.layout.Box
1716
import androidx.compose.foundation.layout.Column
1817
import androidx.compose.foundation.layout.Row
19-
import androidx.compose.foundation.layout.Spacer
2018
import androidx.compose.foundation.layout.WindowInsets
2119
import androidx.compose.foundation.layout.consumeWindowInsets
2220
import androidx.compose.foundation.layout.fillMaxSize
@@ -27,30 +25,23 @@ import androidx.compose.foundation.layout.navigationBarsPadding
2725
import androidx.compose.foundation.layout.padding
2826
import androidx.compose.foundation.layout.statusBars
2927
import androidx.compose.foundation.layout.systemBarsPadding
30-
import androidx.compose.foundation.layout.width
31-
import androidx.compose.foundation.shape.RoundedCornerShape
32-
import androidx.compose.material3.ExperimentalMaterial3Api
3328
import androidx.compose.material3.MaterialTheme
3429
import androidx.compose.runtime.Composable
3530
import androidx.compose.ui.Alignment
3631
import androidx.compose.ui.Modifier
37-
import androidx.compose.ui.draw.clip
3832
import androidx.compose.ui.draw.shadow
3933
import androidx.compose.ui.graphics.RectangleShape
4034
import androidx.compose.ui.platform.LocalView
4135
import androidx.compose.ui.res.stringResource
4236
import androidx.compose.ui.semantics.Role
43-
import androidx.compose.ui.semantics.heading
4437
import androidx.compose.ui.semantics.onClick
4538
import androidx.compose.ui.semantics.role
4639
import androidx.compose.ui.semantics.semantics
4740
import androidx.compose.ui.text.font.FontStyle
4841
import androidx.compose.ui.text.style.TextAlign
49-
import androidx.compose.ui.text.style.TextOverflow
5042
import androidx.compose.ui.tooling.preview.PreviewParameter
5143
import androidx.compose.ui.unit.dp
5244
import io.element.android.compound.theme.ElementTheme
53-
import io.element.android.compound.tokens.generated.CompoundIcons
5445
import io.element.android.features.messages.api.timeline.voicemessages.composer.VoiceMessageComposerEvents
5546
import io.element.android.features.messages.impl.actionlist.ActionListEvents
5647
import io.element.android.features.messages.impl.actionlist.ActionListView
@@ -69,38 +60,30 @@ import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBan
6960
import io.element.android.features.messages.impl.timeline.FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS
7061
import io.element.android.features.messages.impl.timeline.TimelineEvents
7162
import io.element.android.features.messages.impl.timeline.TimelineView
72-
import io.element.android.features.messages.impl.timeline.components.CallMenuItem
7363
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionBottomSheet
7464
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionEvents
7565
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryEvents
7666
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryView
7767
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheet
7868
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetEvents
7969
import io.element.android.features.messages.impl.timeline.model.TimelineItem
70+
import io.element.android.features.messages.impl.topbars.MessagesViewTopBar
71+
import io.element.android.features.messages.impl.topbars.ThreadTopBar
8072
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessagePermissionRationaleDialog
8173
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageSendingFailedDialog
8274
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
83-
import io.element.android.features.roomcall.api.RoomCallState
8475
import io.element.android.libraries.androidutils.ui.hideKeyboard
8576
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
8677
import io.element.android.libraries.designsystem.components.ExpandableBottomSheetLayout
8778
import io.element.android.libraries.designsystem.components.ExpandableBottomSheetLayoutState
88-
import io.element.android.libraries.designsystem.components.avatar.Avatar
89-
import io.element.android.libraries.designsystem.components.avatar.AvatarData
90-
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
91-
import io.element.android.libraries.designsystem.components.avatar.AvatarType
92-
import io.element.android.libraries.designsystem.components.button.BackButton
9379
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
9480
import io.element.android.libraries.designsystem.components.rememberExpandableBottomSheetLayoutState
9581
import io.element.android.libraries.designsystem.preview.ElementPreview
9682
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
9783
import io.element.android.libraries.designsystem.text.toAnnotatedString
9884
import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle
99-
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
100-
import io.element.android.libraries.designsystem.theme.components.Icon
10185
import io.element.android.libraries.designsystem.theme.components.Scaffold
10286
import io.element.android.libraries.designsystem.theme.components.Text
103-
import io.element.android.libraries.designsystem.theme.components.TopAppBar
10487
import io.element.android.libraries.designsystem.utils.HideKeyboardWhenDisposed
10588
import io.element.android.libraries.designsystem.utils.KeepScreenOn
10689
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
@@ -113,14 +96,9 @@ import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
11396
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
11497
import io.element.android.libraries.matrix.api.timeline.Timeline
11598
import io.element.android.libraries.matrix.api.user.MatrixUser
116-
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
117-
import io.element.android.libraries.matrix.ui.model.getAvatarData
11899
import io.element.android.libraries.textcomposer.model.TextEditorState
119100
import io.element.android.libraries.ui.strings.CommonStrings
120101
import io.element.android.wysiwyg.link.Link
121-
import kotlinx.collections.immutable.ImmutableList
122-
import kotlinx.collections.immutable.persistentListOf
123-
import kotlinx.collections.immutable.toImmutableList
124102
import timber.log.Timber
125103
import kotlin.time.Duration.Companion.milliseconds
126104

@@ -517,154 +495,6 @@ private fun MessagesViewComposerBottomSheetContents(
517495
}
518496
}
519497

520-
@OptIn(ExperimentalMaterial3Api::class)
521-
@Composable
522-
private fun MessagesViewTopBar(
523-
roomName: String?,
524-
roomAvatar: AvatarData,
525-
isTombstoned: Boolean,
526-
heroes: ImmutableList<AvatarData>,
527-
roomCallState: RoomCallState,
528-
dmUserIdentityState: IdentityState?,
529-
onRoomDetailsClick: () -> Unit,
530-
onJoinCallClick: () -> Unit,
531-
onBackClick: () -> Unit,
532-
) {
533-
TopAppBar(
534-
navigationIcon = {
535-
BackButton(onClick = onBackClick)
536-
},
537-
title = {
538-
val roundedCornerShape = RoundedCornerShape(8.dp)
539-
Row(
540-
modifier = Modifier
541-
.clip(roundedCornerShape)
542-
.clickable { onRoomDetailsClick() },
543-
horizontalArrangement = Arrangement.spacedBy(4.dp),
544-
verticalAlignment = Alignment.CenterVertically,
545-
) {
546-
val titleModifier = Modifier.weight(1f, fill = false)
547-
RoomAvatarAndNameRow(
548-
roomName = roomName,
549-
roomAvatar = roomAvatar,
550-
isTombstoned = isTombstoned,
551-
heroes = heroes,
552-
modifier = titleModifier
553-
)
554-
555-
when (dmUserIdentityState) {
556-
IdentityState.Verified -> {
557-
Icon(
558-
imageVector = CompoundIcons.Verified(),
559-
tint = ElementTheme.colors.iconSuccessPrimary,
560-
contentDescription = null,
561-
)
562-
}
563-
IdentityState.VerificationViolation -> {
564-
Icon(
565-
imageVector = CompoundIcons.ErrorSolid(),
566-
tint = ElementTheme.colors.iconCriticalPrimary,
567-
contentDescription = null,
568-
)
569-
}
570-
else -> Unit
571-
}
572-
}
573-
},
574-
actions = {
575-
CallMenuItem(
576-
roomCallState = roomCallState,
577-
onJoinCallClick = onJoinCallClick,
578-
)
579-
Spacer(Modifier.width(8.dp))
580-
},
581-
windowInsets = WindowInsets(0.dp)
582-
)
583-
}
584-
585-
@OptIn(ExperimentalMaterial3Api::class)
586-
@Composable
587-
private fun ThreadTopBar(
588-
roomName: String?,
589-
roomAvatarData: AvatarData,
590-
heroes: ImmutableList<AvatarData>,
591-
isTombstoned: Boolean,
592-
onBackClick: () -> Unit,
593-
modifier: Modifier = Modifier,
594-
) {
595-
TopAppBar(
596-
modifier = modifier,
597-
navigationIcon = {
598-
BackButton(onClick = onBackClick)
599-
},
600-
title = {
601-
Row(verticalAlignment = Alignment.CenterVertically) {
602-
Avatar(
603-
avatarData = roomAvatarData,
604-
avatarType = AvatarType.Room(
605-
heroes = heroes,
606-
isTombstoned = isTombstoned,
607-
),
608-
)
609-
Column(
610-
modifier = Modifier.fillMaxWidth()
611-
.padding(horizontal = 8.dp)
612-
.semantics {
613-
heading()
614-
},
615-
) {
616-
Text(
617-
text = stringResource(CommonStrings.common_thread),
618-
style = ElementTheme.typography.fontBodyLgMedium,
619-
)
620-
Text(
621-
text = roomName ?: stringResource(CommonStrings.common_no_room_name),
622-
style = ElementTheme.typography.fontBodySmRegular,
623-
fontStyle = FontStyle.Italic.takeIf { roomName == null },
624-
color = ElementTheme.colors.textSecondary,
625-
maxLines = 1,
626-
overflow = TextOverflow.Ellipsis
627-
)
628-
}
629-
}
630-
}
631-
)
632-
}
633-
634-
@Composable
635-
private fun RoomAvatarAndNameRow(
636-
roomName: String?,
637-
roomAvatar: AvatarData,
638-
heroes: ImmutableList<AvatarData>,
639-
isTombstoned: Boolean,
640-
modifier: Modifier = Modifier
641-
) {
642-
Row(
643-
modifier = modifier,
644-
verticalAlignment = Alignment.CenterVertically
645-
) {
646-
Avatar(
647-
avatarData = roomAvatar,
648-
avatarType = AvatarType.Room(
649-
heroes = heroes,
650-
isTombstoned = isTombstoned,
651-
),
652-
)
653-
Text(
654-
modifier = Modifier
655-
.padding(horizontal = 8.dp)
656-
.semantics {
657-
heading()
658-
},
659-
text = roomName ?: stringResource(CommonStrings.common_no_room_name),
660-
style = ElementTheme.typography.fontBodyLgMedium,
661-
fontStyle = FontStyle.Italic.takeIf { roomName == null },
662-
maxLines = 1,
663-
overflow = TextOverflow.Ellipsis
664-
)
665-
}
666-
}
667-
668498
@Composable
669499
private fun CantSendMessageBanner() {
670500
Row(
@@ -719,58 +549,3 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class)
719549
knockRequestsBannerView = {},
720550
)
721551
}
722-
723-
@PreviewsDayNight
724-
@Composable
725-
internal fun ThreadTopBarPreview() {
726-
ElementPreview {
727-
val name = "Room name"
728-
val initialsAvatarData = AvatarData(
729-
id = "id",
730-
name = name,
731-
url = null,
732-
size = AvatarSize.TimelineRoom,
733-
)
734-
Column {
735-
ThreadTopBar(
736-
roomName = name,
737-
roomAvatarData = initialsAvatarData,
738-
heroes = persistentListOf(),
739-
isTombstoned = false,
740-
onBackClick = {},
741-
)
742-
HorizontalDivider()
743-
ThreadTopBar(
744-
roomName = name,
745-
roomAvatarData = initialsAvatarData,
746-
heroes = aMatrixUserList().map { it.getAvatarData(AvatarSize.TimelineRoom) }.toImmutableList(),
747-
isTombstoned = false,
748-
onBackClick = {},
749-
)
750-
HorizontalDivider()
751-
ThreadTopBar(
752-
roomName = null,
753-
roomAvatarData = initialsAvatarData,
754-
heroes = persistentListOf(),
755-
isTombstoned = false,
756-
onBackClick = {},
757-
)
758-
HorizontalDivider()
759-
ThreadTopBar(
760-
roomName = name,
761-
roomAvatarData = initialsAvatarData.copy(url = "https://some-avatar.jpg"),
762-
heroes = persistentListOf(),
763-
isTombstoned = false,
764-
onBackClick = {},
765-
)
766-
HorizontalDivider()
767-
ThreadTopBar(
768-
roomName = name,
769-
roomAvatarData = initialsAvatarData,
770-
heroes = persistentListOf(),
771-
isTombstoned = true,
772-
onBackClick = {},
773-
)
774-
}
775-
}
776-
}

0 commit comments

Comments
 (0)