Merge pull request #5669 from element-hq/fix/forward-events-from-pinned-media-timeline
Fix forward events from media viewer from pinned media timeline
This commit is contained in:
commit
c13fafd836
32 changed files with 148 additions and 71 deletions
|
|
@ -9,13 +9,14 @@ package io.element.android.x.di
|
||||||
|
|
||||||
import dev.zacsweers.metro.GraphExtension
|
import dev.zacsweers.metro.GraphExtension
|
||||||
import dev.zacsweers.metro.Provides
|
import dev.zacsweers.metro.Provides
|
||||||
|
import io.element.android.appnav.di.TimelineBindings
|
||||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
||||||
@GraphExtension(RoomScope::class)
|
@GraphExtension(RoomScope::class)
|
||||||
interface RoomGraph : NodeFactoriesBindings {
|
interface RoomGraph : NodeFactoriesBindings, TimelineBindings {
|
||||||
@GraphExtension.Factory
|
@GraphExtension.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(
|
fun create(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* 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.appnav.di
|
||||||
|
|
||||||
|
import io.element.android.features.messages.api.pinned.PinnedEventsTimelineProvider
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
||||||
|
|
||||||
|
interface TimelineBindings {
|
||||||
|
val timelineProvider: TimelineProvider
|
||||||
|
val pinnedEventsTimelineProvider: PinnedEventsTimelineProvider
|
||||||
|
}
|
||||||
|
|
@ -22,10 +22,10 @@ import dev.zacsweers.metro.Assisted
|
||||||
import dev.zacsweers.metro.AssistedInject
|
import dev.zacsweers.metro.AssistedInject
|
||||||
import io.element.android.annotations.ContributesNode
|
import io.element.android.annotations.ContributesNode
|
||||||
import io.element.android.appnav.di.RoomGraphFactory
|
import io.element.android.appnav.di.RoomGraphFactory
|
||||||
|
import io.element.android.appnav.di.TimelineBindings
|
||||||
import io.element.android.appnav.room.RoomNavigationTarget
|
import io.element.android.appnav.room.RoomNavigationTarget
|
||||||
import io.element.android.features.forward.api.ForwardEntryPoint
|
import io.element.android.features.forward.api.ForwardEntryPoint
|
||||||
import io.element.android.features.messages.api.MessagesEntryPoint
|
import io.element.android.features.messages.api.MessagesEntryPoint
|
||||||
import io.element.android.features.messages.api.MessagesEntryPointNode
|
|
||||||
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
||||||
import io.element.android.features.space.api.SpaceEntryPoint
|
import io.element.android.features.space.api.SpaceEntryPoint
|
||||||
import io.element.android.libraries.architecture.BackstackView
|
import io.element.android.libraries.architecture.BackstackView
|
||||||
|
|
@ -47,8 +47,6 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -136,8 +134,8 @@ class JoinedRoomLoadedFlowNode(
|
||||||
callback.handlePermalinkClick(data, pushToBackstack)
|
callback.handlePermalinkClick(data, pushToBackstack)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startForwardEventFlow(eventId: EventId) {
|
override fun startForwardEventFlow(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
backstack.push(NavTarget.ForwardEvent(eventId))
|
backstack.push(NavTarget.ForwardEvent(eventId, fromPinnedEvents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return roomDetailsEntryPoint.createNode(
|
return roomDetailsEntryPoint.createNode(
|
||||||
|
|
@ -169,7 +167,11 @@ class JoinedRoomLoadedFlowNode(
|
||||||
createSpaceNode(buildContext)
|
createSpaceNode(buildContext)
|
||||||
}
|
}
|
||||||
is NavTarget.ForwardEvent -> {
|
is NavTarget.ForwardEvent -> {
|
||||||
val timelineProvider = { MutableStateFlow(inputs.room.liveTimeline).asStateFlow() }
|
val timelineProvider = if (navTarget.fromPinnedEvents) {
|
||||||
|
(graph as TimelineBindings).pinnedEventsTimelineProvider
|
||||||
|
} else {
|
||||||
|
(graph as TimelineBindings).timelineProvider
|
||||||
|
}
|
||||||
val params = ForwardEntryPoint.Params(navTarget.eventId, timelineProvider)
|
val params = ForwardEntryPoint.Params(navTarget.eventId, timelineProvider)
|
||||||
val callback = object : ForwardEntryPoint.Callback {
|
val callback = object : ForwardEntryPoint.Callback {
|
||||||
override fun onDone(roomIds: List<RoomId>) {
|
override fun onDone(roomIds: List<RoomId>) {
|
||||||
|
|
@ -228,8 +230,8 @@ class JoinedRoomLoadedFlowNode(
|
||||||
callback.handlePermalinkClick(data, pushToBackstack)
|
callback.handlePermalinkClick(data, pushToBackstack)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forwardEvent(eventId: EventId) {
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
backstack.push(NavTarget.ForwardEvent(eventId))
|
backstack.push(NavTarget.ForwardEvent(eventId, fromPinnedEvents))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToRoom(roomId: RoomId) {
|
override fun navigateToRoom(roomId: RoomId) {
|
||||||
|
|
@ -266,7 +268,7 @@ class JoinedRoomLoadedFlowNode(
|
||||||
data class RoomMemberDetails(val userId: UserId) : NavTarget
|
data class RoomMemberDetails(val userId: UserId) : NavTarget
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class ForwardEvent(val eventId: EventId) : NavTarget
|
data class ForwardEvent(val eventId: EventId, val fromPinnedEvents: Boolean) : NavTarget
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object RoomNotificationSettings : NavTarget
|
data object RoomNotificationSettings : NavTarget
|
||||||
|
|
@ -276,7 +278,7 @@ class JoinedRoomLoadedFlowNode(
|
||||||
val messageNode = waitForChildAttached<Node, NavTarget> { navTarget ->
|
val messageNode = waitForChildAttached<Node, NavTarget> { navTarget ->
|
||||||
navTarget is NavTarget.Messages
|
navTarget is NavTarget.Messages
|
||||||
}
|
}
|
||||||
(messageNode as? MessagesEntryPointNode)?.attachThread(threadId, focusedEventId)
|
(messageNode as? MessagesEntryPoint.NodeProxy)?.attachThread(threadId, focusedEventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ dependencies {
|
||||||
implementation(projects.libraries.designsystem)
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
implementation(projects.libraries.roomselect.api)
|
implementation(projects.libraries.roomselect.api)
|
||||||
|
implementation(projects.libraries.uiStrings)
|
||||||
|
|
||||||
testCommonDependencies(libs, true)
|
testCommonDependencies(libs, true)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
||||||
import io.element.android.libraries.matrix.api.timeline.getActiveTimeline
|
import io.element.android.libraries.matrix.api.timeline.getActiveTimeline
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
class ForwardMessagesPresenter(
|
class ForwardMessagesPresenter(
|
||||||
|
|
@ -63,7 +64,11 @@ class ForwardMessagesPresenter(
|
||||||
roomIds: List<RoomId>,
|
roomIds: List<RoomId>,
|
||||||
) = launch {
|
) = launch {
|
||||||
suspend {
|
suspend {
|
||||||
timelineProvider.getActiveTimeline().forwardEvent(eventId, roomIds).getOrThrow()
|
timelineProvider.getActiveTimeline().forwardEvent(eventId, roomIds)
|
||||||
|
.onFailure {
|
||||||
|
Timber.e(it, "Error while forwarding event")
|
||||||
|
}
|
||||||
|
.getOrThrow()
|
||||||
roomIds
|
roomIds
|
||||||
}.runCatchingUpdatingState(forwardingActionState)
|
}.runCatchingUpdatingState(forwardingActionState)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,13 @@
|
||||||
package io.element.android.features.forward.impl
|
package io.element.android.features.forward.impl
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||||
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
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ForwardMessagesView(
|
fun ForwardMessagesView(
|
||||||
|
|
@ -24,6 +26,9 @@ fun ForwardMessagesView(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
onForwardSuccess(it)
|
onForwardSuccess(it)
|
||||||
},
|
},
|
||||||
|
errorMessage = {
|
||||||
|
stringResource(id = CommonStrings.error_unknown)
|
||||||
|
},
|
||||||
onErrorDismiss = {
|
onErrorDismiss = {
|
||||||
state.eventSink(ForwardMessagesEvents.ClearError)
|
state.eventSink(ForwardMessagesEvents.ClearError)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ interface MessagesEntryPoint : FeatureEntryPoint {
|
||||||
fun navigateToRoomDetails()
|
fun navigateToRoomDetails()
|
||||||
fun navigateToRoomMemberDetails(userId: UserId)
|
fun navigateToRoomMemberDetails(userId: UserId)
|
||||||
fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean)
|
fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean)
|
||||||
fun forwardEvent(eventId: EventId)
|
fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean)
|
||||||
fun navigateToRoom(roomId: RoomId)
|
fun navigateToRoom(roomId: RoomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,8 +47,8 @@ interface MessagesEntryPoint : FeatureEntryPoint {
|
||||||
params: Params,
|
params: Params,
|
||||||
callback: Callback,
|
callback: Callback,
|
||||||
): Node
|
): Node
|
||||||
}
|
|
||||||
|
|
||||||
interface MessagesEntryPointNode {
|
interface NodeProxy {
|
||||||
suspend fun attachThread(threadId: ThreadId, focusedEventId: EventId?)
|
suspend fun attachThread(threadId: ThreadId, focusedEventId: EventId?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* 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.api.pinned
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
||||||
|
|
||||||
|
interface PinnedEventsTimelineProvider : TimelineProvider
|
||||||
|
|
@ -32,10 +32,9 @@ import io.element.android.features.location.api.LocationService
|
||||||
import io.element.android.features.location.api.SendLocationEntryPoint
|
import io.element.android.features.location.api.SendLocationEntryPoint
|
||||||
import io.element.android.features.location.api.ShowLocationEntryPoint
|
import io.element.android.features.location.api.ShowLocationEntryPoint
|
||||||
import io.element.android.features.messages.api.MessagesEntryPoint
|
import io.element.android.features.messages.api.MessagesEntryPoint
|
||||||
import io.element.android.features.messages.api.MessagesEntryPointNode
|
|
||||||
import io.element.android.features.messages.impl.attachments.Attachment
|
import io.element.android.features.messages.impl.attachments.Attachment
|
||||||
import io.element.android.features.messages.impl.attachments.preview.AttachmentsPreviewNode
|
import io.element.android.features.messages.impl.attachments.preview.AttachmentsPreviewNode
|
||||||
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
import io.element.android.features.messages.impl.pinned.DefaultPinnedEventsTimelineProvider
|
||||||
import io.element.android.features.messages.impl.pinned.list.PinnedMessagesListNode
|
import io.element.android.features.messages.impl.pinned.list.PinnedMessagesListNode
|
||||||
import io.element.android.features.messages.impl.report.ReportMessageNode
|
import io.element.android.features.messages.impl.report.ReportMessageNode
|
||||||
import io.element.android.features.messages.impl.threads.ThreadedMessagesNode
|
import io.element.android.features.messages.impl.threads.ThreadedMessagesNode
|
||||||
|
|
@ -115,7 +114,7 @@ class MessagesFlowNode(
|
||||||
private val roomNamesCache: RoomNamesCache,
|
private val roomNamesCache: RoomNamesCache,
|
||||||
private val mentionSpanUpdater: MentionSpanUpdater,
|
private val mentionSpanUpdater: MentionSpanUpdater,
|
||||||
private val mentionSpanTheme: MentionSpanTheme,
|
private val mentionSpanTheme: MentionSpanTheme,
|
||||||
private val pinnedEventsTimelineProvider: PinnedEventsTimelineProvider,
|
private val pinnedEventsTimelineProvider: DefaultPinnedEventsTimelineProvider,
|
||||||
private val timelineController: TimelineController,
|
private val timelineController: TimelineController,
|
||||||
private val knockRequestsListEntryPoint: KnockRequestsListEntryPoint,
|
private val knockRequestsListEntryPoint: KnockRequestsListEntryPoint,
|
||||||
private val dateFormatter: DateFormatter,
|
private val dateFormatter: DateFormatter,
|
||||||
|
|
@ -130,8 +129,7 @@ class MessagesFlowNode(
|
||||||
),
|
),
|
||||||
buildContext = buildContext,
|
buildContext = buildContext,
|
||||||
plugins = plugins,
|
plugins = plugins,
|
||||||
),
|
), MessagesEntryPoint.NodeProxy {
|
||||||
MessagesEntryPointNode {
|
|
||||||
sealed interface NavTarget : Parcelable {
|
sealed interface NavTarget : Parcelable {
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Messages(val focusedEventId: EventId?) : NavTarget
|
data class Messages(val focusedEventId: EventId?) : NavTarget
|
||||||
|
|
@ -315,9 +313,9 @@ class MessagesFlowNode(
|
||||||
this@MessagesFlowNode.viewInTimeline(eventId)
|
this@MessagesFlowNode.viewInTimeline(eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forwardEvent(eventId: EventId) {
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
// Need to go to the parent because of the overlay
|
// Need to go to the parent because of the overlay
|
||||||
callback.forwardEvent(eventId)
|
callback.forwardEvent(eventId, fromPinnedEvents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mediaViewerEntryPoint.createNode(
|
mediaViewerEntryPoint.createNode(
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.pinned
|
package io.element.android.features.messages.impl.pinned
|
||||||
|
|
||||||
import dev.zacsweers.metro.Inject
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import dev.zacsweers.metro.SingleIn
|
import dev.zacsweers.metro.SingleIn
|
||||||
|
import io.element.android.features.messages.api.pinned.PinnedEventsTimelineProvider
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.core.coroutine.mapState
|
import io.element.android.libraries.core.coroutine.mapState
|
||||||
|
|
@ -17,7 +18,6 @@ import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -29,12 +29,12 @@ import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@SingleIn(RoomScope::class)
|
@SingleIn(RoomScope::class)
|
||||||
@Inject
|
@ContributesBinding(RoomScope::class)
|
||||||
class PinnedEventsTimelineProvider(
|
class DefaultPinnedEventsTimelineProvider(
|
||||||
private val room: JoinedRoom,
|
private val room: JoinedRoom,
|
||||||
private val syncService: SyncService,
|
private val syncService: SyncService,
|
||||||
private val dispatchers: CoroutineDispatchers,
|
private val dispatchers: CoroutineDispatchers,
|
||||||
) : TimelineProvider {
|
) : PinnedEventsTimelineProvider {
|
||||||
private val _timelineStateFlow: MutableStateFlow<AsyncData<Timeline>> =
|
private val _timelineStateFlow: MutableStateFlow<AsyncData<Timeline>> =
|
||||||
MutableStateFlow(AsyncData.Uninitialized)
|
MutableStateFlow(AsyncData.Uninitialized)
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import dev.zacsweers.metro.Inject
|
import dev.zacsweers.metro.Inject
|
||||||
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
import io.element.android.features.messages.impl.pinned.DefaultPinnedEventsTimelineProvider
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
|
|
@ -35,7 +35,7 @@ import kotlinx.coroutines.flow.onEach
|
||||||
class PinnedMessagesBannerPresenter(
|
class PinnedMessagesBannerPresenter(
|
||||||
private val room: BaseRoom,
|
private val room: BaseRoom,
|
||||||
private val itemFactory: PinnedMessagesBannerItemFactory,
|
private val itemFactory: PinnedMessagesBannerItemFactory,
|
||||||
private val pinnedEventsTimelineProvider: PinnedEventsTimelineProvider,
|
private val pinnedEventsTimelineProvider: DefaultPinnedEventsTimelineProvider,
|
||||||
) : Presenter<PinnedMessagesBannerState> {
|
) : Presenter<PinnedMessagesBannerState> {
|
||||||
private val pinnedItems = mutableStateOf<AsyncData<ImmutableList<PinnedMessagesBannerItem>>>(AsyncData.Uninitialized)
|
private val pinnedItems = mutableStateOf<AsyncData<ImmutableList<PinnedMessagesBannerItem>>>(AsyncData.Uninitialized)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.features.messages.impl.UserEventPermissions
|
||||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||||
import io.element.android.features.messages.impl.link.LinkState
|
import io.element.android.features.messages.impl.link.LinkState
|
||||||
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
import io.element.android.features.messages.impl.pinned.DefaultPinnedEventsTimelineProvider
|
||||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||||
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
|
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
|
||||||
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
|
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
|
||||||
|
|
@ -66,7 +66,7 @@ class PinnedMessagesListPresenter(
|
||||||
@Assisted private val navigator: PinnedMessagesListNavigator,
|
@Assisted private val navigator: PinnedMessagesListNavigator,
|
||||||
private val room: JoinedRoom,
|
private val room: JoinedRoom,
|
||||||
timelineItemsFactoryCreator: TimelineItemsFactory.Creator,
|
timelineItemsFactoryCreator: TimelineItemsFactory.Creator,
|
||||||
private val timelineProvider: PinnedEventsTimelineProvider,
|
private val timelineProvider: DefaultPinnedEventsTimelineProvider,
|
||||||
private val timelineProtectionPresenter: Presenter<TimelineProtectionState>,
|
private val timelineProtectionPresenter: Presenter<TimelineProtectionState>,
|
||||||
private val linkPresenter: Presenter<LinkState>,
|
private val linkPresenter: Presenter<LinkState>,
|
||||||
private val snackbarDispatcher: SnackbarDispatcher,
|
private val snackbarDispatcher: SnackbarDispatcher,
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ class DefaultMessagesEntryPointTest {
|
||||||
override fun navigateToRoomDetails() = lambdaError()
|
override fun navigateToRoomDetails() = lambdaError()
|
||||||
override fun navigateToRoomMemberDetails(userId: UserId) = lambdaError()
|
override fun navigateToRoomMemberDetails(userId: UserId) = lambdaError()
|
||||||
override fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
|
override fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
|
||||||
override fun forwardEvent(eventId: EventId) = lambdaError()
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) = lambdaError()
|
||||||
override fun navigateToRoom(roomId: RoomId) = lambdaError()
|
override fun navigateToRoom(roomId: RoomId) = lambdaError()
|
||||||
}
|
}
|
||||||
val initialTarget = MessagesEntryPoint.InitialTarget.Messages(focusedEventId = AN_EVENT_ID)
|
val initialTarget = MessagesEntryPoint.InitialTarget.Messages(focusedEventId = AN_EVENT_ID)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
package io.element.android.features.messages.impl.pinned.banner
|
package io.element.android.features.messages.impl.pinned.banner
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
import io.element.android.features.messages.impl.pinned.DefaultPinnedEventsTimelineProvider
|
||||||
import io.element.android.libraries.eventformatter.test.FakePinnedMessagesBannerFormatter
|
import io.element.android.libraries.eventformatter.test.FakePinnedMessagesBannerFormatter
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
|
|
@ -195,7 +195,7 @@ class PinnedMessagesBannerPresenterTest {
|
||||||
internal fun TestScope.createPinnedEventsTimelineProvider(
|
internal fun TestScope.createPinnedEventsTimelineProvider(
|
||||||
room: JoinedRoom = FakeJoinedRoom(),
|
room: JoinedRoom = FakeJoinedRoom(),
|
||||||
syncService: SyncService = FakeSyncService(),
|
syncService: SyncService = FakeSyncService(),
|
||||||
) = PinnedEventsTimelineProvider(
|
) = DefaultPinnedEventsTimelineProvider(
|
||||||
room = room,
|
room = room,
|
||||||
syncService = syncService,
|
syncService = syncService,
|
||||||
dispatchers = testCoroutineDispatchers(),
|
dispatchers = testCoroutineDispatchers(),
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import io.element.android.features.messages.impl.actionlist.anActionListState
|
||||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||||
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactoryCreator
|
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactoryCreator
|
||||||
import io.element.android.features.messages.impl.link.aLinkState
|
import io.element.android.features.messages.impl.link.aLinkState
|
||||||
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
|
import io.element.android.features.messages.impl.pinned.DefaultPinnedEventsTimelineProvider
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
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.designsystem.utils.snackbar.SnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
|
|
@ -300,7 +300,7 @@ class PinnedMessagesListPresenterTest {
|
||||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||||
featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(),
|
featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(),
|
||||||
): PinnedMessagesListPresenter {
|
): PinnedMessagesListPresenter {
|
||||||
val timelineProvider = PinnedEventsTimelineProvider(
|
val timelineProvider = DefaultPinnedEventsTimelineProvider(
|
||||||
room = room,
|
room = room,
|
||||||
syncService = syncService,
|
syncService = syncService,
|
||||||
dispatchers = testCoroutineDispatchers(),
|
dispatchers = testCoroutineDispatchers(),
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ interface RoomDetailsEntryPoint : FeatureEntryPoint {
|
||||||
fun navigateToGlobalNotificationSettings()
|
fun navigateToGlobalNotificationSettings()
|
||||||
fun navigateToRoom(roomId: RoomId, serverNames: List<String>)
|
fun navigateToRoom(roomId: RoomId, serverNames: List<String>)
|
||||||
fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean)
|
fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean)
|
||||||
fun startForwardEventFlow(eventId: EventId)
|
fun startForwardEventFlow(eventId: EventId, fromPinnedEvents: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNode(
|
fun createNode(
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ class RoomDetailsFlowNode(
|
||||||
// Cannot happen
|
// Cannot happen
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forwardEvent(eventId: EventId) {
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
// Cannot happen
|
// Cannot happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -331,8 +331,8 @@ class RoomDetailsFlowNode(
|
||||||
callback.handlePermalinkClick(permalinkData, pushToBackstack = false)
|
callback.handlePermalinkClick(permalinkData, pushToBackstack = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forward(eventId: EventId) {
|
override fun forward(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
callback.startForwardEventFlow(eventId)
|
callback.startForwardEventFlow(eventId, fromPinnedEvents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mediaGalleryEntryPoint.createNode(
|
mediaGalleryEntryPoint.createNode(
|
||||||
|
|
@ -358,8 +358,8 @@ class RoomDetailsFlowNode(
|
||||||
callback.handlePermalinkClick(data, pushToBackstack)
|
callback.handlePermalinkClick(data, pushToBackstack)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forwardEvent(eventId: EventId) {
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
callback.startForwardEventFlow(eventId)
|
callback.startForwardEventFlow(eventId, fromPinnedEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToRoom(roomId: RoomId) {
|
override fun navigateToRoom(roomId: RoomId) {
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ class DefaultRoomDetailsEntryPointTest {
|
||||||
override fun navigateToGlobalNotificationSettings() = lambdaError()
|
override fun navigateToGlobalNotificationSettings() = lambdaError()
|
||||||
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>) = lambdaError()
|
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>) = lambdaError()
|
||||||
override fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
|
override fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
|
||||||
override fun startForwardEventFlow(eventId: EventId) = lambdaError()
|
override fun startForwardEventFlow(eventId: EventId, fromPinnedEvents: Boolean) = lambdaError()
|
||||||
}
|
}
|
||||||
val params = RoomDetailsEntryPoint.Params(
|
val params = RoomDetailsEntryPoint.Params(
|
||||||
initialElement = RoomDetailsEntryPoint.InitialTarget.RoomDetails,
|
initialElement = RoomDetailsEntryPoint.InitialTarget.RoomDetails,
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ class UserProfileFlowNode(
|
||||||
// Cannot happen
|
// Cannot happen
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forwardEvent(eventId: EventId) {
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
// Cannot happen
|
// Cannot happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,6 @@ interface MediaGalleryEntryPoint : FeatureEntryPoint {
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun onBackClick()
|
fun onBackClick()
|
||||||
fun viewInTimeline(eventId: EventId)
|
fun viewInTimeline(eventId: EventId)
|
||||||
fun forward(eventId: EventId)
|
fun forward(eventId: EventId, fromPinnedEvents: Boolean)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ interface MediaViewerEntryPoint : FeatureEntryPoint {
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun onDone()
|
fun onDone()
|
||||||
fun viewInTimeline(eventId: EventId)
|
fun viewInTimeline(eventId: EventId)
|
||||||
fun forwardEvent(eventId: EventId)
|
fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Params(
|
data class Params(
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ class MediaGalleryFlowNode(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forward(eventId: EventId) {
|
override fun forward(eventId: EventId) {
|
||||||
callback.forward(eventId)
|
callback.forward(eventId, fromPinnedEvents = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showItem(item: MediaItem.Event) {
|
override fun showItem(item: MediaItem.Event) {
|
||||||
|
|
@ -119,9 +119,9 @@ class MediaGalleryFlowNode(
|
||||||
callback.viewInTimeline(eventId)
|
callback.viewInTimeline(eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun forwardEvent(eventId: EventId) {
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
// Need to go to the parent because of the overlay
|
// Need to go to the parent because of the overlay
|
||||||
callback.forward(eventId)
|
callback.forward(eventId, fromPinnedEvents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mediaViewerEntryPoint.createNode(
|
mediaViewerEntryPoint.createNode(
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
|
||||||
interface MediaViewerNavigator {
|
interface MediaViewerNavigator {
|
||||||
fun onViewInTimelineClick(eventId: EventId)
|
fun onViewInTimelineClick(eventId: EventId)
|
||||||
fun onForwardClick(eventId: EventId)
|
fun onForwardClick(eventId: EventId, fromPinnedEvents: Boolean)
|
||||||
fun onItemDeleted()
|
fun onItemDeleted()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ class MediaViewerNode(
|
||||||
callback.viewInTimeline(eventId)
|
callback.viewInTimeline(eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onForwardClick(eventId: EventId) {
|
override fun onForwardClick(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
callback.forwardEvent(eventId)
|
callback.forwardEvent(eventId, fromPinnedEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemDeleted() {
|
override fun onItemDeleted() {
|
||||||
|
|
@ -81,11 +81,7 @@ class MediaViewerNode(
|
||||||
timelineMediaGalleryDataSource
|
timelineMediaGalleryDataSource
|
||||||
} else {
|
} else {
|
||||||
// Can we use a specific timeline?
|
// Can we use a specific timeline?
|
||||||
val timelineMode = when (val mode = inputs.mode) {
|
val timelineMode = inputs.mode.getTimelineMode()
|
||||||
is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> mode.timelineMode
|
|
||||||
is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> mode.timelineMode
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
when (timelineMode) {
|
when (timelineMode) {
|
||||||
null -> timelineMediaGalleryDataSource
|
null -> timelineMediaGalleryDataSource
|
||||||
Timeline.Mode.Live,
|
Timeline.Mode.Live,
|
||||||
|
|
@ -149,3 +145,11 @@ class MediaViewerNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun MediaViewerEntryPoint.MediaViewerMode.getTimelineMode(): Timeline.Mode? {
|
||||||
|
return when (this) {
|
||||||
|
is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> timelineMode
|
||||||
|
is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> timelineMode
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
||||||
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
|
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
|
||||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||||
|
|
@ -119,7 +120,10 @@ class MediaViewerPresenter(
|
||||||
}
|
}
|
||||||
is MediaViewerEvents.Forward -> {
|
is MediaViewerEvents.Forward -> {
|
||||||
mediaBottomSheetState = MediaBottomSheetState.Hidden
|
mediaBottomSheetState = MediaBottomSheetState.Hidden
|
||||||
navigator.onForwardClick(event.eventId)
|
navigator.onForwardClick(
|
||||||
|
eventId = event.eventId,
|
||||||
|
fromPinnedEvents = inputs.mode.getTimelineMode() == Timeline.Mode.PinnedEvents,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is MediaViewerEvents.OpenInfo -> coroutineScope.launch {
|
is MediaViewerEvents.OpenInfo -> coroutineScope.launch {
|
||||||
mediaBottomSheetState = MediaBottomSheetState.MediaDetailsBottomSheetState(
|
mediaBottomSheetState = MediaBottomSheetState.MediaDetailsBottomSheetState(
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ class SingleMediaGalleryDataSource(
|
||||||
override fun start() = Unit
|
override fun start() = Unit
|
||||||
override fun groupedMediaItemsFlow() = flowOf(AsyncData.Success(data))
|
override fun groupedMediaItemsFlow() = flowOf(AsyncData.Success(data))
|
||||||
override fun getLastData(): AsyncData<GroupedMediaItems> = AsyncData.Success(data)
|
override fun getLastData(): AsyncData<GroupedMediaItems> = AsyncData.Success(data)
|
||||||
|
|
||||||
override suspend fun loadMore(direction: Timeline.PaginationDirection) = Unit
|
override suspend fun loadMore(direction: Timeline.PaginationDirection) = Unit
|
||||||
override suspend fun deleteItem(eventId: EventId) = Unit
|
override suspend fun deleteItem(eventId: EventId) = Unit
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ class DefaultMediaGalleryEntryPointTest {
|
||||||
val callback = object : MediaGalleryEntryPoint.Callback {
|
val callback = object : MediaGalleryEntryPoint.Callback {
|
||||||
override fun onBackClick() = lambdaError()
|
override fun onBackClick() = lambdaError()
|
||||||
override fun viewInTimeline(eventId: EventId) = lambdaError()
|
override fun viewInTimeline(eventId: EventId) = lambdaError()
|
||||||
override fun forward(eventId: EventId) = lambdaError()
|
override fun forward(eventId: EventId, fromPinnedEvents: Boolean) = lambdaError()
|
||||||
}
|
}
|
||||||
val result = entryPoint.createNode(
|
val result = entryPoint.createNode(
|
||||||
parentNode = parentNode,
|
parentNode = parentNode,
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ class DefaultMediaViewerEntryPointTest {
|
||||||
val callback = object : MediaViewerEntryPoint.Callback {
|
val callback = object : MediaViewerEntryPoint.Callback {
|
||||||
override fun onDone() = lambdaError()
|
override fun onDone() = lambdaError()
|
||||||
override fun viewInTimeline(eventId: EventId) = lambdaError()
|
override fun viewInTimeline(eventId: EventId) = lambdaError()
|
||||||
override fun forwardEvent(eventId: EventId) = lambdaError()
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) = lambdaError()
|
||||||
}
|
}
|
||||||
val params = createMediaViewerEntryPointParams()
|
val params = createMediaViewerEntryPointParams()
|
||||||
val result = entryPoint.createNode(
|
val result = entryPoint.createNode(
|
||||||
|
|
@ -118,7 +118,7 @@ class DefaultMediaViewerEntryPointTest {
|
||||||
val callback = object : MediaViewerEntryPoint.Callback {
|
val callback = object : MediaViewerEntryPoint.Callback {
|
||||||
override fun onDone() = lambdaError()
|
override fun onDone() = lambdaError()
|
||||||
override fun viewInTimeline(eventId: EventId) = lambdaError()
|
override fun viewInTimeline(eventId: EventId) = lambdaError()
|
||||||
override fun forwardEvent(eventId: EventId) = lambdaError()
|
override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) = lambdaError()
|
||||||
}
|
}
|
||||||
val params = entryPoint.createParamsForAvatar(
|
val params = entryPoint.createParamsForAvatar(
|
||||||
filename = "fn",
|
filename = "fn",
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,15 @@ import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
|
|
||||||
class FakeMediaViewerNavigator(
|
class FakeMediaViewerNavigator(
|
||||||
private val onViewInTimelineClickLambda: (EventId) -> Unit = { lambdaError() },
|
private val onViewInTimelineClickLambda: (EventId) -> Unit = { lambdaError() },
|
||||||
private val onForwardClickLambda: (EventId) -> Unit = { lambdaError() },
|
private val onForwardClickLambda: (EventId, Boolean) -> Unit = { _, _ -> lambdaError() },
|
||||||
private val onItemDeletedLambda: () -> Unit = { lambdaError() },
|
private val onItemDeletedLambda: () -> Unit = { lambdaError() },
|
||||||
) : MediaViewerNavigator {
|
) : MediaViewerNavigator {
|
||||||
override fun onViewInTimelineClick(eventId: EventId) {
|
override fun onViewInTimelineClick(eventId: EventId) {
|
||||||
onViewInTimelineClickLambda(eventId)
|
onViewInTimelineClickLambda(eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onForwardClick(eventId: EventId) {
|
override fun onForwardClick(eventId: EventId, fromPinnedEvents: Boolean) {
|
||||||
onForwardClickLambda(eventId)
|
onForwardClickLambda(eventId, fromPinnedEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemDeleted() {
|
override fun onItemDeleted() {
|
||||||
|
|
|
||||||
|
|
@ -785,7 +785,7 @@ class MediaViewerPresenterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - forward hides the bottom sheet and invokes the navigator`() = runTest {
|
fun `present - forward hides the bottom sheet and invokes the navigator`() = runTest {
|
||||||
val onForwardClickLambda = lambdaRecorder<EventId, Unit> { }
|
val onForwardClickLambda = lambdaRecorder<EventId, Boolean, Unit> { _, _ -> }
|
||||||
val navigator = FakeMediaViewerNavigator(
|
val navigator = FakeMediaViewerNavigator(
|
||||||
onForwardClickLambda = onForwardClickLambda,
|
onForwardClickLambda = onForwardClickLambda,
|
||||||
)
|
)
|
||||||
|
|
@ -804,7 +804,35 @@ class MediaViewerPresenterTest {
|
||||||
initialState.eventSink(MediaViewerEvents.Forward(AN_EVENT_ID))
|
initialState.eventSink(MediaViewerEvents.Forward(AN_EVENT_ID))
|
||||||
val finalState = awaitItem()
|
val finalState = awaitItem()
|
||||||
assertThat(finalState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
|
assertThat(finalState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
|
||||||
onForwardClickLambda.assertions().isCalledOnce().with(value(AN_EVENT_ID))
|
onForwardClickLambda.assertions().isCalledOnce()
|
||||||
|
.with(value(AN_EVENT_ID), value(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - forward from pinned events hides the bottom sheet and invokes the navigator`() = runTest {
|
||||||
|
val onForwardClickLambda = lambdaRecorder<EventId, Boolean, Unit> { _, _ -> }
|
||||||
|
val navigator = FakeMediaViewerNavigator(
|
||||||
|
onForwardClickLambda = onForwardClickLambda,
|
||||||
|
)
|
||||||
|
val presenter = createMediaViewerPresenter(
|
||||||
|
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode = Timeline.Mode.PinnedEvents),
|
||||||
|
localMediaFactory = localMediaFactory,
|
||||||
|
mediaViewerNavigator = navigator,
|
||||||
|
room = FakeJoinedRoom(
|
||||||
|
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink(MediaViewerEvents.OpenInfo(aMediaViewerPageData()))
|
||||||
|
val withBottomSheetState = awaitItem()
|
||||||
|
assertThat(withBottomSheetState.mediaBottomSheetState).isInstanceOf(MediaBottomSheetState.MediaDetailsBottomSheetState::class.java)
|
||||||
|
initialState.eventSink(MediaViewerEvents.Forward(AN_EVENT_ID))
|
||||||
|
val finalState = awaitItem()
|
||||||
|
assertThat(finalState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
|
||||||
|
onForwardClickLambda.assertions().isCalledOnce()
|
||||||
|
.with(value(AN_EVENT_ID), value(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:5c6ab936964323971e9b4927684e3ae2da96884b340569aebe6e6a711bd6c241
|
oid sha256:9bd3fe043d7fffab7b19b5af9de7ef58ce8d2d97018a058b5b3c94cb55b277b9
|
||||||
size 8446
|
size 11273
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:cd3611749f6ad60bc647236c5a10694b8ac9d1aa84e546740c1bf85df277c6f9
|
oid sha256:97bc2d4c9621a21533da2d35abe90a5e1c1ef1bc356a6342736b61f7be8d8e3b
|
||||||
size 7668
|
size 10357
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue