Pinned events : simplify poll content view
This commit is contained in:
@@ -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) =
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PollAnswerItem>,
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user