Skip to content

Commit 86afffb

Browse files
authored
Merge pull request #4274 from element-hq/feature/bma/mediaTimelineImprovment
Update Matrix Room API and allow media swipe on pinned event only.
2 parents 2518191 + f36e341 commit 86afffb

File tree

31 files changed

+294
-183
lines changed

31 files changed

+294
-183
lines changed

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkData
7171
import io.element.android.libraries.matrix.api.room.MatrixRoom
7272
import io.element.android.libraries.matrix.api.room.alias.matches
7373
import io.element.android.libraries.matrix.api.room.joinedRoomMembers
74+
import io.element.android.libraries.matrix.api.timeline.Timeline
7475
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
7576
import io.element.android.libraries.matrix.ui.messages.LocalRoomMemberProfilesCache
7677
import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache
@@ -187,8 +188,11 @@ class MessagesFlowNode @AssistedInject constructor(
187188
callbacks.forEach { it.onRoomDetailsClick() }
188189
}
189190

190-
override fun onEventClick(event: TimelineItem.Event): Boolean {
191-
return processEventClick(event)
191+
override fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean {
192+
return processEventClick(
193+
timelineMode = if (isLive) Timeline.Mode.LIVE else Timeline.Mode.FOCUSED_ON_EVENT,
194+
event = event,
195+
)
192196
}
193197

194198
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) {
@@ -316,7 +320,10 @@ class MessagesFlowNode @AssistedInject constructor(
316320
NavTarget.PinnedMessagesList -> {
317321
val callback = object : PinnedMessagesListNode.Callback {
318322
override fun onEventClick(event: TimelineItem.Event) {
319-
processEventClick(event)
323+
processEventClick(
324+
timelineMode = Timeline.Mode.PINNED_EVENTS,
325+
event = event,
326+
)
320327
}
321328

322329
override fun onUserDataClick(userId: UserId) {
@@ -358,11 +365,14 @@ class MessagesFlowNode @AssistedInject constructor(
358365
callbacks.forEach { it.onPermalinkClick(permalinkData, pushToBackstack = false) }
359366
}
360367

361-
private fun processEventClick(event: TimelineItem.Event): Boolean {
368+
private fun processEventClick(
369+
timelineMode: Timeline.Mode,
370+
event: TimelineItem.Event,
371+
): Boolean {
362372
val navTarget = when (event.content) {
363373
is TimelineItemImageContent -> {
364374
buildMediaViewerNavTarget(
365-
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos,
375+
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
366376
event = event,
367377
content = event.content,
368378
mediaSource = event.content.mediaSource,
@@ -374,7 +384,7 @@ class MessagesFlowNode @AssistedInject constructor(
374384
if encrypted on certain bridges */
375385
event.content.preferredMediaSource?.let { preferredMediaSource ->
376386
buildMediaViewerNavTarget(
377-
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos,
387+
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
378388
event = event,
379389
content = event.content,
380390
mediaSource = preferredMediaSource,
@@ -384,7 +394,7 @@ class MessagesFlowNode @AssistedInject constructor(
384394
}
385395
is TimelineItemVideoContent -> {
386396
buildMediaViewerNavTarget(
387-
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos,
397+
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
388398
event = event,
389399
content = event.content,
390400
mediaSource = event.content.mediaSource,
@@ -393,7 +403,7 @@ class MessagesFlowNode @AssistedInject constructor(
393403
}
394404
is TimelineItemFileContent -> {
395405
buildMediaViewerNavTarget(
396-
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios,
406+
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode),
397407
event = event,
398408
content = event.content,
399409
mediaSource = event.content.mediaSource,
@@ -402,7 +412,7 @@ class MessagesFlowNode @AssistedInject constructor(
402412
}
403413
is TimelineItemAudioContent -> {
404414
buildMediaViewerNavTarget(
405-
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios,
415+
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode),
406416
event = event,
407417
content = event.content,
408418
mediaSource = event.content.mediaSource,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class MessagesNode @AssistedInject constructor(
8989

9090
interface Callback : Plugin {
9191
fun onRoomDetailsClick()
92-
fun onEventClick(event: TimelineItem.Event): Boolean
92+
fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean
9393
fun onPreviewAttachments(attachments: ImmutableList<Attachment>)
9494
fun onUserDataClick(userId: UserId)
9595
fun onPermalinkClick(data: PermalinkData)
@@ -120,12 +120,12 @@ class MessagesNode @AssistedInject constructor(
120120
callbacks.forEach { it.onRoomDetailsClick() }
121121
}
122122

123-
private fun onEventClick(event: TimelineItem.Event): Boolean {
123+
private fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean {
124124
// Note: cannot use `callbacks.all { it.onEventClick(event) }` because:
125125
// - if callbacks is empty, it will return true and we want to return false.
126126
// - if a callback returns false, the other callback will not be invoked.
127127
return callbacks.takeIf { it.isNotEmpty() }
128-
?.map { it.onEventClick(event) }
128+
?.map { it.onEventClick(isLive, event) }
129129
?.all { it }
130130
.orFalse()
131131
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ fun MessagesView(
111111
state: MessagesState,
112112
onBackClick: () -> Unit,
113113
onRoomDetailsClick: () -> Unit,
114-
onEventContentClick: (event: TimelineItem.Event) -> Boolean,
114+
onEventContentClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean,
115115
onUserDataClick: (UserId) -> Unit,
116116
onLinkClick: (String, Boolean) -> Unit,
117117
onSendLocationClick: () -> Unit,
@@ -142,7 +142,7 @@ fun MessagesView(
142142

143143
fun onContentClick(event: TimelineItem.Event) {
144144
Timber.v("onMessageClick= ${event.id}")
145-
val hideKeyboard = onEventContentClick(event)
145+
val hideKeyboard = onEventContentClick(state.timelineState.isLive, event)
146146
if (hideKeyboard) {
147147
localView.hideKeyboard()
148148
}
@@ -544,7 +544,7 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class)
544544
state = state,
545545
onBackClick = {},
546546
onRoomDetailsClick = {},
547-
onEventContentClick = { false },
547+
onEventContentClick = { _, _ -> false },
548548
onUserDataClick = {},
549549
onLinkClick = { _, _ -> },
550550
onSendLocationClick = {},

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ internal fun MessagesViewWithIdentityChangePreview(
3333
),
3434
onBackClick = {},
3535
onRoomDetailsClick = {},
36-
onEventContentClick = { false },
36+
onEventContentClick = { _, _ -> false },
3737
onUserDataClick = {},
3838
onLinkClick = { _, _ -> },
3939
onSendLocationClick = {},

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import io.element.android.libraries.di.RoomScope
1414
import io.element.android.libraries.di.SingleIn
1515
import io.element.android.libraries.featureflag.api.FeatureFlagService
1616
import io.element.android.libraries.featureflag.api.FeatureFlags
17+
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
1718
import io.element.android.libraries.matrix.api.room.MatrixRoom
1819
import io.element.android.libraries.matrix.api.sync.SyncService
1920
import io.element.android.libraries.matrix.api.timeline.Timeline
@@ -104,7 +105,7 @@ class PinnedEventsTimelineProvider @Inject constructor(
104105
is AsyncData.Uninitialized, is AsyncData.Failure -> {
105106
timelineStateFlow.emit(AsyncData.Loading())
106107
withContext(dispatchers.io) {
107-
room.pinnedEventsTimeline()
108+
room.createTimeline(CreateTimelineParams.PinnedOnly)
108109
}
109110
.fold(
110111
{ timelineStateFlow.emit(AsyncData.Success(it)) },

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.squareup.anvil.annotations.ContributesBinding
1111
import io.element.android.libraries.di.RoomScope
1212
import io.element.android.libraries.di.SingleIn
1313
import io.element.android.libraries.matrix.api.core.EventId
14+
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
1415
import io.element.android.libraries.matrix.api.room.MatrixRoom
1516
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
1617
import io.element.android.libraries.matrix.api.timeline.Timeline
@@ -64,7 +65,7 @@ class TimelineController @Inject constructor(
6465
}
6566

6667
suspend fun focusOnEvent(eventId: EventId): Result<Unit> {
67-
return room.timelineFocusedOnEvent(eventId)
68+
return room.createTimeline(CreateTimelineParams.Focused(eventId))
6869
.onFailure {
6970
if (it is CancellationException) {
7071
throw it

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ import io.element.android.libraries.matrix.api.core.UserId
5454
import io.element.android.libraries.matrix.test.AN_EVENT_ID
5555
import io.element.android.libraries.testtags.TestTags
5656
import io.element.android.libraries.ui.strings.CommonStrings
57-
import io.element.android.tests.testutils.EnsureCalledOnceWithParam
57+
import io.element.android.tests.testutils.EnsureCalledOnceWithTwoParamsAndResult
5858
import io.element.android.tests.testutils.EnsureNeverCalled
5959
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
60-
import io.element.android.tests.testutils.EnsureNeverCalledWithParamAndResult
6160
import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams
61+
import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParamsAndResult
6262
import io.element.android.tests.testutils.EventsRecorder
6363
import io.element.android.tests.testutils.clickOn
6464
import io.element.android.tests.testutils.ensureCalledOnce
@@ -129,8 +129,9 @@ class MessagesViewTest {
129129
eventSink = eventsRecorder
130130
)
131131
val timelineItem = state.timelineState.timelineItems.first()
132-
val callback = EnsureCalledOnceWithParam(
133-
expectedParam = timelineItem,
132+
val callback = EnsureCalledOnceWithTwoParamsAndResult(
133+
expectedParam1 = true,
134+
expectedParam2 = timelineItem,
134135
result = true,
135136
)
136137
rule.setMessagesView(
@@ -513,7 +514,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setMessa
513514
state: MessagesState,
514515
onBackClick: () -> Unit = EnsureNeverCalled(),
515516
onRoomDetailsClick: () -> Unit = EnsureNeverCalled(),
516-
onEventClick: (event: TimelineItem.Event) -> Boolean = EnsureNeverCalledWithParamAndResult(),
517+
onEventClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean = EnsureNeverCalledWithTwoParamsAndResult(),
517518
onUserDataClick: (UserId) -> Unit = EnsureNeverCalledWithParam(),
518519
onLinkClick: (String, Boolean) -> Unit = EnsureNeverCalledWithTwoParams(),
519520
onSendLocationClick: () -> Unit = EnsureNeverCalled(),

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class PinnedMessagesBannerPresenterTest {
5555
@Test
5656
fun `present - loading state`() = runTest {
5757
val room = FakeMatrixRoom(
58-
pinnedEventsTimelineResult = { Result.success(FakeTimeline()) }
58+
createTimelineResult = { Result.success(FakeTimeline()) }
5959
).apply {
6060
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
6161
}
@@ -86,7 +86,7 @@ class PinnedMessagesBannerPresenterTest {
8686
)
8787
)
8888
val room = FakeMatrixRoom(
89-
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }
89+
createTimelineResult = { Result.success(pinnedEventsTimeline) }
9090
).apply {
9191
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID, AN_EVENT_ID_2)))
9292
}
@@ -125,7 +125,7 @@ class PinnedMessagesBannerPresenterTest {
125125
)
126126
)
127127
val room = FakeMatrixRoom(
128-
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }
128+
createTimelineResult = { Result.success(pinnedEventsTimeline) }
129129
).apply {
130130
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID, AN_EVENT_ID_2)))
131131
}
@@ -160,7 +160,7 @@ class PinnedMessagesBannerPresenterTest {
160160
@Test
161161
fun `present - timeline failed`() = runTest {
162162
val room = FakeMatrixRoom(
163-
pinnedEventsTimelineResult = { Result.failure(Exception()) }
163+
createTimelineResult = { Result.failure(Exception()) }
164164
).apply {
165165
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
166166
}

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class PinnedMessagesListPresenterTest {
8383
@Test
8484
fun `present - timeline failure state`() = runTest {
8585
val room = FakeMatrixRoom(
86-
pinnedEventsTimelineResult = { Result.failure(RuntimeException()) },
86+
createTimelineResult = { Result.failure(RuntimeException()) },
8787
canRedactOwnResult = { Result.success(true) },
8888
canRedactOtherResult = { Result.success(true) },
8989
canUserPinUnpinResult = { Result.success(true) },
@@ -102,7 +102,7 @@ class PinnedMessagesListPresenterTest {
102102
@Test
103103
fun `present - empty state`() = runTest {
104104
val room = FakeMatrixRoom(
105-
pinnedEventsTimelineResult = { Result.success(FakeTimeline()) },
105+
createTimelineResult = { Result.success(FakeTimeline()) },
106106
canRedactOwnResult = { Result.success(true) },
107107
canRedactOtherResult = { Result.success(true) },
108108
canUserPinUnpinResult = { Result.success(true) },
@@ -122,7 +122,7 @@ class PinnedMessagesListPresenterTest {
122122
fun `present - filled state`() = runTest {
123123
val pinnedEventsTimeline = createPinnedMessagesTimeline()
124124
val room = FakeMatrixRoom(
125-
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) },
125+
createTimelineResult = { Result.success(pinnedEventsTimeline) },
126126
canRedactOwnResult = { Result.success(true) },
127127
canRedactOtherResult = { Result.success(true) },
128128
canUserPinUnpinResult = { Result.success(true) },
@@ -149,7 +149,7 @@ class PinnedMessagesListPresenterTest {
149149
val pinnedEventsTimeline = createPinnedMessagesTimeline()
150150
val analyticsService = FakeAnalyticsService()
151151
val room = FakeMatrixRoom(
152-
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) },
152+
createTimelineResult = { Result.success(pinnedEventsTimeline) },
153153
canRedactOwnResult = { Result.success(true) },
154154
canRedactOtherResult = { Result.success(true) },
155155
canUserPinUnpinResult = { Result.success(true) },
@@ -195,7 +195,7 @@ class PinnedMessagesListPresenterTest {
195195
}
196196
val pinnedEventsTimeline = createPinnedMessagesTimeline()
197197
val room = FakeMatrixRoom(
198-
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) },
198+
createTimelineResult = { Result.success(pinnedEventsTimeline) },
199199
canRedactOwnResult = { Result.success(true) },
200200
canRedactOtherResult = { Result.success(true) },
201201
canUserPinUnpinResult = { Result.success(true) },
@@ -224,7 +224,7 @@ class PinnedMessagesListPresenterTest {
224224
}
225225
val pinnedEventsTimeline = createPinnedMessagesTimeline()
226226
val room = FakeMatrixRoom(
227-
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) },
227+
createTimelineResult = { Result.success(pinnedEventsTimeline) },
228228
canRedactOwnResult = { Result.success(true) },
229229
canRedactOtherResult = { Result.success(true) },
230230
canUserPinUnpinResult = { Result.success(true) },
@@ -253,7 +253,7 @@ class PinnedMessagesListPresenterTest {
253253
}
254254
val pinnedEventsTimeline = createPinnedMessagesTimeline()
255255
val room = FakeMatrixRoom(
256-
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) },
256+
createTimelineResult = { Result.success(pinnedEventsTimeline) },
257257
canRedactOwnResult = { Result.success(true) },
258258
canRedactOtherResult = { Result.success(true) },
259259
canUserPinUnpinResult = { Result.success(true) },

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class TimelineControllerTest {
3131
val detachedTimeline = FakeTimeline(name = "detached")
3232
val matrixRoom = FakeMatrixRoom(
3333
liveTimeline = liveTimeline,
34-
timelineFocusedOnEventResult = { Result.success(detachedTimeline) }
34+
createTimelineResult = { Result.success(detachedTimeline) }
3535
)
3636
val sut = TimelineController(matrixRoom)
3737

@@ -63,7 +63,7 @@ class TimelineControllerTest {
6363
var callNumber = 0
6464
val matrixRoom = FakeMatrixRoom(
6565
liveTimeline = liveTimeline,
66-
timelineFocusedOnEventResult = {
66+
createTimelineResult = {
6767
callNumber++
6868
when (callNumber) {
6969
1 -> Result.success(detachedTimeline1)
@@ -117,7 +117,7 @@ class TimelineControllerTest {
117117
val detachedTimeline = FakeTimeline(name = "detached")
118118
val matrixRoom = FakeMatrixRoom(
119119
liveTimeline = liveTimeline,
120-
timelineFocusedOnEventResult = { Result.success(detachedTimeline) }
120+
createTimelineResult = { Result.success(detachedTimeline) }
121121
)
122122
val sut = TimelineController(matrixRoom)
123123
sut.activeTimelineFlow().test {
@@ -167,7 +167,7 @@ class TimelineControllerTest {
167167
}
168168
val matrixRoom = FakeMatrixRoom(
169169
liveTimeline = liveTimeline,
170-
timelineFocusedOnEventResult = { Result.success(detachedTimeline) }
170+
createTimelineResult = { Result.success(detachedTimeline) }
171171
)
172172
val sut = TimelineController(matrixRoom)
173173
sut.activeTimelineFlow().test {
@@ -192,7 +192,7 @@ class TimelineControllerTest {
192192
val detachedTimeline = FakeTimeline(name = "detached")
193193
val matrixRoom = FakeMatrixRoom(
194194
liveTimeline = liveTimeline,
195-
timelineFocusedOnEventResult = { Result.success(detachedTimeline) }
195+
createTimelineResult = { Result.success(detachedTimeline) }
196196
)
197197
val sut = TimelineController(matrixRoom)
198198

0 commit comments

Comments
 (0)