Merge pull request #4376 from ShadowRZ/features/shadowrz/long-press-link-copy

Long press link to copy URL to clipboard
This commit is contained in:
Benoit Marty 2025-03-10 09:17:16 +01:00 committed by GitHub
commit ae2a281c47
13 changed files with 74 additions and 0 deletions

View file

@ -8,10 +8,12 @@
package io.element.android.features.messages.impl.pinned.list package io.element.android.features.messages.impl.pinned.list
import android.content.Context import android.content.Context
import android.view.HapticFeedbackConstants
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.Plugin
@ -23,6 +25,7 @@ import io.element.android.features.messages.impl.actionlist.ActionListPresenter
import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories
import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactories import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactories
import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.libraries.androidutils.system.copyToClipboard
import io.element.android.libraries.androidutils.system.openUrlInExternalApp import io.element.android.libraries.androidutils.system.openUrlInExternalApp
import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
@ -30,6 +33,7 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.ui.strings.CommonStrings
@ContributesNode(RoomScope::class) @ContributesNode(RoomScope::class)
class PinnedMessagesListNode @AssistedInject constructor( class PinnedMessagesListNode @AssistedInject constructor(
@ -98,6 +102,7 @@ class PinnedMessagesListNode @AssistedInject constructor(
LocalTimelineItemPresenterFactories provides timelineItemPresenterFactories, LocalTimelineItemPresenterFactories provides timelineItemPresenterFactories,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val view = LocalView.current
val state = presenter.present() val state = presenter.present()
PinnedMessagesListView( PinnedMessagesListView(
state = state, state = state,
@ -105,6 +110,15 @@ class PinnedMessagesListNode @AssistedInject constructor(
onEventClick = ::onEventClick, onEventClick = ::onEventClick,
onUserDataClick = ::onUserDataClick, onUserDataClick = ::onUserDataClick,
onLinkClick = { url -> onLinkClick(context, url) }, onLinkClick = { url -> onLinkClick(context, url) },
onLinkLongClick = {
view.performHapticFeedback(
HapticFeedbackConstants.LONG_PRESS
)
context.copyToClipboard(
it,
context.getString(CommonStrings.common_copied_to_clipboard)
)
},
modifier = modifier modifier = modifier
) )
} }

View file

@ -58,6 +58,7 @@ fun PinnedMessagesListView(
onEventClick: (event: TimelineItem.Event) -> Unit, onEventClick: (event: TimelineItem.Event) -> Unit,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Scaffold( Scaffold(
@ -78,6 +79,7 @@ fun PinnedMessagesListView(
onEventClick = onEventClick, onEventClick = onEventClick,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onErrorDismiss = onBackClick, onErrorDismiss = onBackClick,
modifier = Modifier modifier = Modifier
.padding(padding) .padding(padding)
@ -112,6 +114,7 @@ private fun PinnedMessagesListContent(
onEventClick: (event: TimelineItem.Event) -> Unit, onEventClick: (event: TimelineItem.Event) -> Unit,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onErrorDismiss: () -> Unit, onErrorDismiss: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -130,6 +133,7 @@ private fun PinnedMessagesListContent(
onEventClick = onEventClick, onEventClick = onEventClick,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
) )
PinnedMessagesListState.Loading -> { PinnedMessagesListState.Loading -> {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
@ -166,6 +170,7 @@ private fun PinnedMessagesListLoaded(
onEventClick: (event: TimelineItem.Event) -> Unit, onEventClick: (event: TimelineItem.Event) -> Unit,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
fun onActionSelected(timelineItemAction: TimelineItemAction, event: TimelineItem.Event) { fun onActionSelected(timelineItemAction: TimelineItemAction, event: TimelineItem.Event) {
@ -216,6 +221,7 @@ private fun PinnedMessagesListLoaded(
focusedEventId = null, focusedEventId = null,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onContentClick = onEventClick, onContentClick = onEventClick,
onLongClick = ::onMessageLongClick, onLongClick = ::onMessageLongClick,
inReplyToClick = {}, inReplyToClick = {},
@ -233,6 +239,7 @@ private fun PinnedMessagesListLoaded(
onContentClick = { onEventClick(event) }, onContentClick = { onEventClick(event) },
onLongClick = { onMessageLongClick(event) }, onLongClick = { onMessageLongClick(event) },
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
modifier = contentModifier, modifier = contentModifier,
onContentLayoutChange = onContentLayoutChange onContentLayoutChange = onContentLayoutChange
) )
@ -248,6 +255,7 @@ private fun TimelineItemEventContentViewWrapper(
timelineProtectionState: TimelineProtectionState, timelineProtectionState: TimelineProtectionState,
onContentClick: () -> Unit, onContentClick: () -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onLongClick: (() -> Unit)?, onLongClick: (() -> Unit)?,
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -264,6 +272,7 @@ private fun TimelineItemEventContentViewWrapper(
hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId), hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId),
onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) }, onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) },
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
eventSink = { }, eventSink = { },
modifier = modifier, modifier = modifier,
onContentClick = onContentClick, onContentClick = onContentClick,
@ -283,5 +292,6 @@ internal fun PinnedMessagesListViewPreview(@PreviewParameter(PinnedMessagesListS
onEventClick = { }, onEventClick = { },
onUserDataClick = {}, onUserDataClick = {},
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
) )
} }

View file

@ -7,6 +7,7 @@
package io.element.android.features.messages.impl.timeline package io.element.android.features.messages.impl.timeline
import android.view.HapticFeedbackConstants
import android.view.accessibility.AccessibilityManager import android.view.accessibility.AccessibilityManager
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
@ -41,6 +42,7 @@ import androidx.compose.ui.draw.rotate
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
@ -59,6 +61,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentProvider import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentProvider
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
import io.element.android.libraries.androidutils.system.copyToClipboard
import io.element.android.libraries.designsystem.components.dialogs.AlertDialog import io.element.android.libraries.designsystem.components.dialogs.AlertDialog
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -106,6 +109,7 @@ fun TimelineView(
} }
val context = LocalContext.current val context = LocalContext.current
val view = LocalView.current
// Disable reverse layout when TalkBack is enabled to avoid incorrect ordering issues seen in the current Compose UI version // Disable reverse layout when TalkBack is enabled to avoid incorrect ordering issues seen in the current Compose UI version
val useReverseLayout = remember { val useReverseLayout = remember {
val accessibilityManager = context.getSystemService(AccessibilityManager::class.java) val accessibilityManager = context.getSystemService(AccessibilityManager::class.java)
@ -116,6 +120,16 @@ fun TimelineView(
state.eventSink(TimelineEvents.FocusOnEvent(eventId)) state.eventSink(TimelineEvents.FocusOnEvent(eventId))
} }
fun onLinkLongClick(link: String) {
view.performHapticFeedback(
HapticFeedbackConstants.LONG_PRESS
)
context.copyToClipboard(
link,
context.getString(CommonStrings.common_copied_to_clipboard)
)
}
// Animate alpha when timeline is first displayed, to avoid flashes or glitching when viewing rooms // Animate alpha when timeline is first displayed, to avoid flashes or glitching when viewing rooms
AnimatedVisibility(visible = true, enter = fadeIn()) { AnimatedVisibility(visible = true, enter = fadeIn()) {
Box(modifier) { Box(modifier) {
@ -141,6 +155,7 @@ fun TimelineView(
focusedEventId = state.focusedEventId, focusedEventId = state.focusedEventId,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = ::onLinkLongClick,
onContentClick = onContentClick, onContentClick = onContentClick,
onLongClick = onMessageLongClick, onLongClick = onMessageLongClick,
inReplyToClick = ::inReplyToClick, inReplyToClick = ::inReplyToClick,

View file

@ -33,6 +33,7 @@ internal fun ATimelineItemEventRow(
onEventClick = {}, onEventClick = {},
onLongClick = {}, onLongClick = {},
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
onUserDataClick = {}, onUserDataClick = {},
inReplyToClick = {}, inReplyToClick = {},
onReactionClick = { _, _ -> }, onReactionClick = { _, _ -> },

View file

@ -118,6 +118,7 @@ fun TimelineItemEventRow(
onEventClick: () -> Unit, onEventClick: () -> Unit,
onLongClick: () -> Unit, onLongClick: () -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
inReplyToClick: (EventId) -> Unit, inReplyToClick: (EventId) -> Unit,
onReactionClick: (emoji: String, eventId: TimelineItem.Event) -> Unit, onReactionClick: (emoji: String, eventId: TimelineItem.Event) -> Unit,
@ -138,6 +139,7 @@ fun TimelineItemEventRow(
onLongClick = onLongClick, onLongClick = onLongClick,
onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) }, onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) },
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
eventSink = eventSink, eventSink = eventSink,
modifier = contentModifier, modifier = contentModifier,
onContentLayoutChange = onContentLayoutChange onContentLayoutChange = onContentLayoutChange

View file

@ -46,6 +46,7 @@ fun TimelineItemGroupedEventsRow(
inReplyToClick: (EventId) -> Unit, inReplyToClick: (EventId) -> Unit,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onReactionClick: (key: String, TimelineItem.Event) -> Unit, onReactionClick: (key: String, TimelineItem.Event) -> Unit,
onReactionLongClick: (key: String, TimelineItem.Event) -> Unit, onReactionLongClick: (key: String, TimelineItem.Event) -> Unit,
onMoreReactionsClick: (TimelineItem.Event) -> Unit, onMoreReactionsClick: (TimelineItem.Event) -> Unit,
@ -59,6 +60,7 @@ fun TimelineItemGroupedEventsRow(
hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId), hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId),
onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) }, onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) },
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
eventSink = eventSink, eventSink = eventSink,
modifier = contentModifier, modifier = contentModifier,
onContentClick = null, onContentClick = null,
@ -87,6 +89,7 @@ fun TimelineItemGroupedEventsRow(
inReplyToClick = inReplyToClick, inReplyToClick = inReplyToClick,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onReactionClick = onReactionClick, onReactionClick = onReactionClick,
onReactionLongClick = onReactionLongClick, onReactionLongClick = onReactionLongClick,
onMoreReactionsClick = onMoreReactionsClick, onMoreReactionsClick = onMoreReactionsClick,
@ -112,6 +115,7 @@ private fun TimelineItemGroupedEventsRowContent(
inReplyToClick: (EventId) -> Unit, inReplyToClick: (EventId) -> Unit,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onReactionClick: (key: String, TimelineItem.Event) -> Unit, onReactionClick: (key: String, TimelineItem.Event) -> Unit,
onReactionLongClick: (key: String, TimelineItem.Event) -> Unit, onReactionLongClick: (key: String, TimelineItem.Event) -> Unit,
onMoreReactionsClick: (TimelineItem.Event) -> Unit, onMoreReactionsClick: (TimelineItem.Event) -> Unit,
@ -125,6 +129,7 @@ private fun TimelineItemGroupedEventsRowContent(
hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId), hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId),
onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) }, onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) },
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
eventSink = eventSink, eventSink = eventSink,
modifier = contentModifier, modifier = contentModifier,
onContentClick = null, onContentClick = null,
@ -156,6 +161,7 @@ private fun TimelineItemGroupedEventsRowContent(
focusedEventId = focusedEventId, focusedEventId = focusedEventId,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onContentClick = onClick, onContentClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
inReplyToClick = inReplyToClick, inReplyToClick = inReplyToClick,
@ -199,6 +205,7 @@ internal fun TimelineItemGroupedEventsRowContentExpandedPreview() = ElementPrevi
isLastOutgoingMessage = false, isLastOutgoingMessage = false,
onClick = {}, onClick = {},
onLongClick = {}, onLongClick = {},
onLinkLongClick = {},
inReplyToClick = {}, inReplyToClick = {},
onUserDataClick = {}, onUserDataClick = {},
onLinkClick = {}, onLinkClick = {},
@ -224,6 +231,7 @@ internal fun TimelineItemGroupedEventsRowContentCollapsePreview() = ElementPrevi
isLastOutgoingMessage = false, isLastOutgoingMessage = false,
onClick = {}, onClick = {},
onLongClick = {}, onLongClick = {},
onLinkLongClick = {},
inReplyToClick = {}, inReplyToClick = {},
onUserDataClick = {}, onUserDataClick = {},
onLinkClick = {}, onLinkClick = {},

View file

@ -43,6 +43,7 @@ internal fun TimelineItemRow(
focusedEventId: EventId?, focusedEventId: EventId?,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onContentClick: (TimelineItem.Event) -> Unit, onContentClick: (TimelineItem.Event) -> Unit,
onLongClick: (TimelineItem.Event) -> Unit, onLongClick: (TimelineItem.Event) -> Unit,
inReplyToClick: (EventId) -> Unit, inReplyToClick: (EventId) -> Unit,
@ -63,6 +64,7 @@ internal fun TimelineItemRow(
onContentClick = { onContentClick(event) }, onContentClick = { onContentClick(event) },
onLongClick = { onLongClick(event) }, onLongClick = { onLongClick(event) },
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
eventSink = eventSink, eventSink = eventSink,
modifier = contentModifier, modifier = contentModifier,
onContentLayoutChange = onContentLayoutChange onContentLayoutChange = onContentLayoutChange
@ -122,6 +124,7 @@ internal fun TimelineItemRow(
onEventClick = { onContentClick(timelineItem) }, onEventClick = { onContentClick(timelineItem) },
onLongClick = { onLongClick(timelineItem) }, onLongClick = { onLongClick(timelineItem) },
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
inReplyToClick = inReplyToClick, inReplyToClick = inReplyToClick,
onReactionClick = onReactionClick, onReactionClick = onReactionClick,
@ -150,6 +153,7 @@ internal fun TimelineItemRow(
inReplyToClick = inReplyToClick, inReplyToClick = inReplyToClick,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onReactionClick = onReactionClick, onReactionClick = onReactionClick,
onReactionLongClick = onReactionLongClick, onReactionLongClick = onReactionLongClick,
onMoreReactionsClick = onMoreReactionsClick, onMoreReactionsClick = onMoreReactionsClick,

View file

@ -71,6 +71,7 @@ fun TimelineItemStateEventRow(
TimelineItemEventContentView( TimelineItemEventContentView(
content = event.content, content = event.content,
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
hideMediaContent = false, hideMediaContent = false,
onShowContentClick = {}, onShowContentClick = {},
eventSink = eventSink, eventSink = eventSink,

View file

@ -40,6 +40,7 @@ fun TimelineItemEventContentView(
onLongClick: (() -> Unit)?, onLongClick: (() -> Unit)?,
onShowContentClick: () -> Unit, onShowContentClick: () -> Unit,
onLinkClick: (url: String) -> Unit, onLinkClick: (url: String) -> Unit,
onLinkLongClick: (String) -> Unit,
eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit, eventSink: (TimelineEvents.EventFromTimelineItem) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit = {}, onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit = {},
@ -60,6 +61,7 @@ fun TimelineItemEventContentView(
content = content, content = content,
modifier = modifier, modifier = modifier,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onContentLayoutChange = onContentLayoutChange onContentLayoutChange = onContentLayoutChange
) )
is TimelineItemUnknownContent -> TimelineItemUnknownView( is TimelineItemUnknownContent -> TimelineItemUnknownView(
@ -78,6 +80,7 @@ fun TimelineItemEventContentView(
onLongClick = onLongClick, onLongClick = onLongClick,
onShowContentClick = onShowContentClick, onShowContentClick = onShowContentClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onContentLayoutChange = onContentLayoutChange, onContentLayoutChange = onContentLayoutChange,
modifier = modifier, modifier = modifier,
) )
@ -96,6 +99,7 @@ fun TimelineItemEventContentView(
onLongClick = onLongClick, onLongClick = onLongClick,
onShowContentClick = onShowContentClick, onShowContentClick = onShowContentClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
onContentLayoutChange = onContentLayoutChange, onContentLayoutChange = onContentLayoutChange,
modifier = modifier modifier = modifier
) )

View file

@ -65,6 +65,7 @@ fun TimelineItemImageView(
onContentClick: (() -> Unit)?, onContentClick: (() -> Unit)?,
onLongClick: (() -> Unit)?, onLongClick: (() -> Unit)?,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onShowContentClick: () -> Unit, onShowContentClick: () -> Unit,
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -120,6 +121,7 @@ fun TimelineItemImageView(
text = caption, text = caption,
style = ElementRichTextEditorStyle.textStyle(), style = ElementRichTextEditorStyle.textStyle(),
onLinkClickedListener = onLinkClick, onLinkClickedListener = onLinkClick,
onLinkLongClickedListener = onLinkLongClick,
releaseOnDetach = false, releaseOnDetach = false,
onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange), onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange),
) )
@ -138,6 +140,7 @@ internal fun TimelineItemImageViewPreview(@PreviewParameter(TimelineItemImageCon
onContentClick = {}, onContentClick = {},
onLongClick = {}, onLongClick = {},
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
onContentLayoutChange = {}, onContentLayoutChange = {},
) )
} }
@ -152,6 +155,7 @@ internal fun TimelineItemImageViewHideMediaContentPreview() = ElementPreview {
onContentClick = {}, onContentClick = {},
onLongClick = {}, onLongClick = {},
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
onContentLayoutChange = {}, onContentLayoutChange = {},
) )
} }

View file

@ -46,6 +46,7 @@ import io.element.android.wysiwyg.compose.EditorStyledText
fun TimelineItemTextView( fun TimelineItemTextView(
content: TimelineItemTextBasedContent, content: TimelineItemTextBasedContent,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit = {}, onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit = {},
) { ) {
@ -64,6 +65,7 @@ fun TimelineItemTextView(
EditorStyledText( EditorStyledText(
text = body, text = body,
onLinkClickedListener = onLinkClick, onLinkClickedListener = onLinkClick,
onLinkLongClickedListener = onLinkLongClick,
style = ElementRichTextEditorStyle.textStyle(), style = ElementRichTextEditorStyle.textStyle(),
onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange), onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange),
releaseOnDetach = false, releaseOnDetach = false,
@ -115,6 +117,7 @@ internal fun TimelineItemTextViewPreview(
TimelineItemTextView( TimelineItemTextView(
content = content, content = content,
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
) )
} }
@ -127,6 +130,7 @@ internal fun TimelineItemTextViewWithLinkifiedUrlPreview() = ElementPreview {
TimelineItemTextView( TimelineItemTextView(
content = content, content = content,
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
) )
} }
@ -139,5 +143,6 @@ internal fun TimelineItemTextViewWithLinkifiedUrlAndNestedParenthesisPreview() =
TimelineItemTextView( TimelineItemTextView(
content = content, content = content,
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
) )
} }

View file

@ -74,6 +74,7 @@ fun TimelineItemVideoView(
onLongClick: (() -> Unit)?, onLongClick: (() -> Unit)?,
onShowContentClick: () -> Unit, onShowContentClick: () -> Unit,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
onLinkLongClick: (String) -> Unit,
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -147,6 +148,7 @@ fun TimelineItemVideoView(
.widthIn(min = MIN_HEIGHT_IN_DP.dp * aspectRatio, max = MAX_HEIGHT_IN_DP.dp * aspectRatio), .widthIn(min = MIN_HEIGHT_IN_DP.dp * aspectRatio, max = MAX_HEIGHT_IN_DP.dp * aspectRatio),
text = caption, text = caption,
onLinkClickedListener = onLinkClick, onLinkClickedListener = onLinkClick,
onLinkLongClickedListener = onLinkLongClick,
style = ElementRichTextEditorStyle.textStyle(), style = ElementRichTextEditorStyle.textStyle(),
releaseOnDetach = false, releaseOnDetach = false,
onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange), onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange),
@ -166,6 +168,7 @@ internal fun TimelineItemVideoViewPreview(@PreviewParameter(TimelineItemVideoCon
onContentClick = {}, onContentClick = {},
onLongClick = {}, onLongClick = {},
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
onContentLayoutChange = {}, onContentLayoutChange = {},
) )
} }
@ -180,6 +183,7 @@ internal fun TimelineItemVideoViewHideMediaContentPreview() = ElementPreview {
onContentClick = {}, onContentClick = {},
onLongClick = {}, onLongClick = {},
onLinkClick = {}, onLinkClick = {},
onLinkLongClick = {},
onContentLayoutChange = {}, onContentLayoutChange = {},
) )
} }

View file

@ -100,6 +100,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setPinne
onEventClick: (event: TimelineItem.Event) -> Unit = EnsureNeverCalledWithParam(), onEventClick: (event: TimelineItem.Event) -> Unit = EnsureNeverCalledWithParam(),
onUserDataClick: (UserId) -> Unit = EnsureNeverCalledWithParam(), onUserDataClick: (UserId) -> Unit = EnsureNeverCalledWithParam(),
onLinkClick: (String) -> Unit = EnsureNeverCalledWithParam(), onLinkClick: (String) -> Unit = EnsureNeverCalledWithParam(),
onLinkLongClick: (String) -> Unit = EnsureNeverCalledWithParam(),
) { ) {
setSafeContent { setSafeContent {
PinnedMessagesListView( PinnedMessagesListView(
@ -108,6 +109,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setPinne
onEventClick = onEventClick, onEventClick = onEventClick,
onUserDataClick = onUserDataClick, onUserDataClick = onUserDataClick,
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
onLinkLongClick = onLinkLongClick,
) )
} }
} }