From bd327aac8881590e2ba3511a521c0ff1b0a2c56e Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 30 Aug 2024 18:27:19 +0200 Subject: [PATCH] Pinned events : simplify poll content view --- .../pinned/list/PinnedMessagesListView.kt | 40 ++++++++++- .../components/TimelineItemEventRow.kt | 39 +++++----- .../TimelineItemGroupedEventsRow.kt | 24 ++++++- .../timeline/components/TimelineItemRow.kt | 16 ++++- .../poll/api/pollcontent/PollContentView.kt | 34 +-------- .../poll/api/pollcontent/PollTitleView.kt | 71 +++++++++++++++++++ 6 files changed, 167 insertions(+), 57 deletions(-) create mode 100644 features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollTitleView.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt index 5518e2b36a..9ccc0ab767 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt @@ -36,7 +36,11 @@ import io.element.android.features.messages.impl.actionlist.ActionListEvents import io.element.android.features.messages.impl.actionlist.ActionListView import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.timeline.components.TimelineItemRow +import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView +import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent +import io.element.android.features.poll.api.pollcontent.PollTitleView import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.icons.CompoundDrawables @@ -70,8 +74,8 @@ fun PinnedMessagesListView( onUserDataClick = onUserDataClick, onLinkClick = onLinkClick, modifier = Modifier - .padding(padding) - .consumeWindowInsets(padding), + .padding(padding) + .consumeWindowInsets(padding), ) } ) @@ -208,11 +212,43 @@ private fun PinnedMessagesListLoaded( onSwipeToReply = {}, onJoinCallClick = {}, onShieldClick = {}, + eventContentView = { event, contentModifier, onContentLayoutChange -> + TimelineItemEventContentViewWrapper( + event = event, + onLinkClick = onLinkClick, + modifier = contentModifier, + onContentLayoutChange = onContentLayoutChange + ) + }, ) } } } +@Composable +private fun TimelineItemEventContentViewWrapper( + event: TimelineItem.Event, + onLinkClick: (String) -> Unit, + modifier: Modifier = Modifier, + onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, +) { + if (event.content is TimelineItemPollContent) { + PollTitleView( + title = event.content.question, + isPollEnded = event.content.isEnded, + modifier = modifier + ) + } else { + TimelineItemEventContentView( + content = event.content, + onLinkClick = onLinkClick, + eventSink = { }, + modifier = modifier, + onContentLayoutChange = onContentLayoutChange + ) + } +} + @PreviewsDayNight @Composable fun PinnedMessagesTimelineViewPreview(@PreviewParameter(PinnedMessagesTimelineStateProvider::class) state: PinnedMessagesListState) = diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 8a6fccf2eb..15caee8091 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -129,7 +129,16 @@ fun TimelineItemEventRow( onReadReceiptClick: (event: TimelineItem.Event) -> Unit, onSwipeToReply: () -> Unit, eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + eventContentView: @Composable (Modifier, (ContentAvoidingLayoutData) -> Unit) -> Unit = { contentModifier, onContentLayoutChange -> + TimelineItemEventContentView( + content = event.content, + onLinkClick = onLinkClick, + eventSink = eventSink, + modifier = contentModifier, + onContentLayoutChange = onContentLayoutChange + ) + }, ) { val coroutineScope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } @@ -188,8 +197,7 @@ fun TimelineItemEventRow( onReactionClick = { emoji -> onReactionClick(emoji, event) }, onReactionLongClick = { emoji -> onReactionLongClick(emoji, event) }, onMoreReactionsClick = { onMoreReactionsClick(event) }, - onLinkClick = onLinkClick, - eventSink = eventSink, + eventContentView = eventContentView, ) } } @@ -207,8 +215,7 @@ fun TimelineItemEventRow( onReactionClick = { emoji -> onReactionClick(emoji, event) }, onReactionLongClick = { emoji -> onReactionLongClick(emoji, event) }, onMoreReactionsClick = { onMoreReactionsClick(event) }, - onLinkClick = onLinkClick, - eventSink = eventSink, + eventContentView = eventContentView, ) } // Read receipts / Send state @@ -263,9 +270,8 @@ private fun TimelineItemEventRowContent( onReactionClick: (emoji: String) -> Unit, onReactionLongClick: (emoji: String) -> Unit, onMoreReactionsClick: (event: TimelineItem.Event) -> Unit, - onLinkClick: (String) -> Unit, - eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit, modifier: Modifier = Modifier, + eventContentView: @Composable (Modifier, (ContentAvoidingLayoutData) -> Unit) -> Unit, ) { fun ConstrainScope.linkStartOrEnd(event: TimelineItem.Event) = if (event.isMine) { end.linkTo(parent.end) @@ -328,8 +334,7 @@ private fun TimelineItemEventRowContent( onShieldClick = onShieldClick, onMessageLongClick = onLongClick, inReplyToClick = inReplyToClick, - onLinkClick = onLinkClick, - eventSink = eventSink, + eventContentView = eventContentView, ) } @@ -389,12 +394,11 @@ private fun MessageEventBubbleContent( onShieldClick: (MessageShield) -> Unit, onMessageLongClick: () -> Unit, inReplyToClick: () -> Unit, - onLinkClick: (String) -> Unit, - eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit, @SuppressLint("ModifierParameter") // need to rename this modifier to prevent linter false positives @Suppress("ModifierNaming") bubbleModifier: Modifier = Modifier, + eventContentView: @Composable (Modifier, (ContentAvoidingLayoutData) -> Unit) -> Unit, ) { // Long clicks are not not automatically propagated from a `clickable` // to its `combinedClickable` parent so we do it manually @@ -521,15 +525,10 @@ private fun MessageEventBubbleContent( onShieldClick = onShieldClick, canShrinkContent = canShrinkContent, modifier = timestampLayoutModifier, - ) { onContentLayoutChange -> - TimelineItemEventContentView( - content = event.content, - onLinkClick = onLinkClick, - eventSink = eventSink, - onContentLayoutChange = onContentLayoutChange, - modifier = contentModifier - ) - } + content = { onContentLayoutChange -> + eventContentView(contentModifier, onContentLayoutChange) + } + ) } val inReplyTo = @Composable { inReplyTo: InReplyToDetails -> diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt index bb1cb2b2df..478f745ed6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt @@ -28,7 +28,9 @@ import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineRoomInfo import io.element.android.features.messages.impl.timeline.aGroupedEvents import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo +import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView import io.element.android.features.messages.impl.timeline.components.group.GroupHeaderView +import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewState import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView import io.element.android.features.messages.impl.timeline.model.TimelineItem @@ -56,7 +58,16 @@ fun TimelineItemGroupedEventsRow( onMoreReactionsClick: (TimelineItem.Event) -> Unit, onReadReceiptClick: (TimelineItem.Event) -> Unit, eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + eventContentView: @Composable (TimelineItem.Event, Modifier, (ContentAvoidingLayoutData) -> Unit) -> Unit = { event, contentModifier, onContentLayoutChange -> + TimelineItemEventContentView( + content = event.content, + onLinkClick = onLinkClick, + eventSink = eventSink, + modifier = contentModifier, + onContentLayoutChange = onContentLayoutChange + ) + }, ) { val isExpanded = rememberSaveable(key = timelineItem.identifier()) { mutableStateOf(false) } @@ -84,6 +95,7 @@ fun TimelineItemGroupedEventsRow( onReadReceiptClick = onReadReceiptClick, eventSink = eventSink, modifier = modifier, + eventContentView = eventContentView, ) } @@ -108,6 +120,15 @@ private fun TimelineItemGroupedEventsRowContent( onReadReceiptClick: (TimelineItem.Event) -> Unit, eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit, modifier: Modifier = Modifier, + eventContentView: @Composable (TimelineItem.Event, Modifier, (ContentAvoidingLayoutData) -> Unit) -> Unit = { event, contentModifier, onContentLayoutChange -> + TimelineItemEventContentView( + content = event.content, + onLinkClick = onLinkClick, + eventSink = eventSink, + modifier = contentModifier, + onContentLayoutChange = onContentLayoutChange + ) + }, ) { Column(modifier = modifier.animateContentSize()) { GroupHeaderView( @@ -142,6 +163,7 @@ private fun TimelineItemGroupedEventsRowContent( eventSink = eventSink, onSwipeToReply = {}, onJoinCallClick = {}, + eventContentView = eventContentView, ) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt index 9cbcf20bef..8f659c594f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt @@ -29,6 +29,8 @@ import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineRoomInfo +import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView +import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent @@ -59,7 +61,16 @@ internal fun TimelineItemRow( onSwipeToReply: (TimelineItem.Event) -> Unit, onJoinCallClick: () -> Unit, eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + eventContentView: @Composable (TimelineItem.Event, Modifier, (ContentAvoidingLayoutData) -> Unit) -> Unit = { event, contentModifier, onContentLayoutChange -> + TimelineItemEventContentView( + content = event.content, + onLinkClick = onLinkClick, + eventSink = eventSink, + modifier = contentModifier, + onContentLayoutChange = onContentLayoutChange + ) + }, ) { val backgroundModifier = if (timelineItem.isEvent(focusedEventId)) { val focusedEventOffset = if ((timelineItem as? TimelineItem.Event)?.showSenderInformation == true) { @@ -122,6 +133,9 @@ internal fun TimelineItemRow( onReadReceiptClick = onReadReceiptClick, onSwipeToReply = { onSwipeToReply(timelineItem) }, eventSink = eventSink, + eventContentView = { contentModifier, onContentLayoutChange -> + eventContentView(timelineItem, contentModifier, onContentLayoutChange) + }, ) } } diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt index e5c445bd4e..7d8394f30d 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt @@ -19,10 +19,8 @@ package io.element.android.features.poll.api.pollcontent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectableGroup import androidx.compose.runtime.Composable @@ -36,12 +34,10 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role 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.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button -import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.poll.PollAnswer @@ -117,7 +113,7 @@ fun PollContentView( modifier = modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp), ) { - PollTitle(title = question, isPollEnded = isPollEnded) + PollTitleView(title = question, isPollEnded = isPollEnded) PollAnswers(answerItems = answerItems, onSelectAnswer = ::onSelectAnswer) @@ -139,34 +135,6 @@ fun PollContentView( } } -@Composable -private fun PollTitle( - title: String, - isPollEnded: Boolean, -) { - Row( - horizontalArrangement = Arrangement.spacedBy(12.dp), - ) { - if (isPollEnded) { - Icon( - imageVector = CompoundIcons.PollsEnd(), - contentDescription = stringResource(id = CommonStrings.a11y_poll_end), - modifier = Modifier.size(22.dp) - ) - } else { - Icon( - imageVector = CompoundIcons.Polls(), - contentDescription = stringResource(id = CommonStrings.a11y_poll), - modifier = Modifier.size(22.dp) - ) - } - Text( - text = title, - style = ElementTheme.typography.fontBodyLgMedium - ) - } -} - @Composable private fun PollAnswers( answerItems: ImmutableList, diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollTitleView.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollTitleView.kt new file mode 100644 index 0000000000..5a772dec26 --- /dev/null +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollTitleView.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.poll.api.pollcontent + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +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.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun PollTitleView( + title: String, + isPollEnded: Boolean, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + if (isPollEnded) { + Icon( + imageVector = CompoundIcons.PollsEnd(), + contentDescription = stringResource(id = CommonStrings.a11y_poll_end), + modifier = Modifier.size(22.dp) + ) + } else { + Icon( + imageVector = CompoundIcons.Polls(), + contentDescription = stringResource(id = CommonStrings.a11y_poll), + modifier = Modifier.size(22.dp) + ) + } + Text( + text = title, + style = ElementTheme.typography.fontBodyLgMedium + ) + } +} + +@PreviewsDayNight +@Composable +internal fun PollTitleViewPreview() = ElementPreview { + PollTitleView( + title = "What is your favorite color?", + isPollEnded = false + ) +}