Media Gallery
This commit is contained in:
parent
61805646c8
commit
28725a364f
69 changed files with 3822 additions and 56 deletions
|
|
@ -107,6 +107,11 @@ interface MatrixRoom : Closeable {
|
|||
*/
|
||||
suspend fun pinnedEventsTimeline(): Result<Timeline>
|
||||
|
||||
/**
|
||||
* Create a new timeline for the media events of the room.
|
||||
*/
|
||||
suspend fun mediaTimeline(): Result<Timeline>
|
||||
|
||||
fun destroy()
|
||||
|
||||
suspend fun subscribeToSync()
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ interface Timeline : AutoCloseable {
|
|||
enum class Mode {
|
||||
LIVE,
|
||||
FOCUSED_ON_EVENT,
|
||||
PINNED_EVENTS
|
||||
PINNED_EVENTS,
|
||||
MEDIA,
|
||||
}
|
||||
|
||||
val membershipChangeEventReceived: Flow<Unit>
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ import org.matrix.rustcomponents.sdk.IdentityStatusChangeListener
|
|||
import org.matrix.rustcomponents.sdk.RoomInfo
|
||||
import org.matrix.rustcomponents.sdk.RoomInfoListener
|
||||
import org.matrix.rustcomponents.sdk.RoomListItem
|
||||
import org.matrix.rustcomponents.sdk.RoomMessageEventMessageType
|
||||
import org.matrix.rustcomponents.sdk.TypingNotificationsListener
|
||||
import org.matrix.rustcomponents.sdk.UserPowerLevelUpdate
|
||||
import org.matrix.rustcomponents.sdk.WidgetCapabilities
|
||||
|
|
@ -223,6 +224,26 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun mediaTimeline(): Result<Timeline> {
|
||||
return runCatching {
|
||||
innerRoom.messageFilteredTimeline(
|
||||
internalIdPrefix = "MediaGallery_",
|
||||
allowedMessageTypes = listOf(
|
||||
RoomMessageEventMessageType.FILE,
|
||||
RoomMessageEventMessageType.IMAGE,
|
||||
RoomMessageEventMessageType.VIDEO,
|
||||
RoomMessageEventMessageType.AUDIO,
|
||||
)
|
||||
).let { inner ->
|
||||
createTimeline(inner, mode = Timeline.Mode.MEDIA)
|
||||
}
|
||||
}.onFailure {
|
||||
if (it is CancellationException) {
|
||||
throw it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
roomCoroutineScope.cancel()
|
||||
liveTimeline.close()
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ import kotlinx.coroutines.flow.onCompletion
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.EditedContent
|
||||
import org.matrix.rustcomponents.sdk.FormattedBody
|
||||
|
|
@ -170,26 +172,36 @@ class RustTimeline(
|
|||
}
|
||||
}
|
||||
|
||||
private val backwardsPaginationMutex = Mutex()
|
||||
private val forwardsPaginationMutex = Mutex()
|
||||
|
||||
private fun getPaginationMutex(direction: Timeline.PaginationDirection) = when (direction) {
|
||||
Timeline.PaginationDirection.BACKWARDS -> backwardsPaginationMutex
|
||||
Timeline.PaginationDirection.FORWARDS -> forwardsPaginationMutex
|
||||
}
|
||||
|
||||
// Use NonCancellable to avoid breaking the timeline when the coroutine is cancelled.
|
||||
override suspend fun paginate(direction: Timeline.PaginationDirection): Result<Boolean> = withContext(NonCancellable) {
|
||||
withContext(dispatcher) {
|
||||
initLatch.await()
|
||||
runCatching {
|
||||
if (!canPaginate(direction)) throw TimelineException.CannotPaginate
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = true) }
|
||||
when (direction) {
|
||||
Timeline.PaginationDirection.BACKWARDS -> inner.paginateBackwards(PAGINATION_SIZE.toUShort())
|
||||
Timeline.PaginationDirection.FORWARDS -> inner.focusedPaginateForwards(PAGINATION_SIZE.toUShort())
|
||||
getPaginationMutex(direction).withLock {
|
||||
runCatching {
|
||||
if (!canPaginate(direction)) throw TimelineException.CannotPaginate
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = true) }
|
||||
when (direction) {
|
||||
Timeline.PaginationDirection.BACKWARDS -> inner.paginateBackwards(PAGINATION_SIZE.toUShort())
|
||||
Timeline.PaginationDirection.FORWARDS -> inner.focusedPaginateForwards(PAGINATION_SIZE.toUShort())
|
||||
}
|
||||
}.onFailure { error ->
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = false) }
|
||||
if (error is TimelineException.CannotPaginate) {
|
||||
Timber.d("Can't paginate $direction on room ${matrixRoom.roomId} with paginationStatus: ${backPaginationStatus.value}")
|
||||
} else {
|
||||
Timber.e(error, "Error paginating $direction on room ${matrixRoom.roomId}")
|
||||
}
|
||||
}.onSuccess { hasReachedEnd ->
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = false, hasMoreToLoad = !hasReachedEnd) }
|
||||
}
|
||||
}.onFailure { error ->
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = false) }
|
||||
if (error is TimelineException.CannotPaginate) {
|
||||
Timber.d("Can't paginate $direction on room ${matrixRoom.roomId} with paginationStatus: ${backPaginationStatus.value}")
|
||||
} else {
|
||||
Timber.e(error, "Error paginating $direction on room ${matrixRoom.roomId}")
|
||||
}
|
||||
}.onSuccess { hasReachedEnd ->
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = false, hasMoreToLoad = !hasReachedEnd) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ class FakeMatrixRoom(
|
|||
private val getMembersResult: (Int) -> Result<List<RoomMember>> = { lambdaError() },
|
||||
private val timelineFocusedOnEventResult: (EventId) -> Result<Timeline> = { lambdaError() },
|
||||
private val pinnedEventsTimelineResult: () -> Result<Timeline> = { lambdaError() },
|
||||
private val mediaTimelineResult: () -> Result<Timeline> = { lambdaError() },
|
||||
private val setSendQueueEnabledLambda: (Boolean) -> Unit = { _: Boolean -> },
|
||||
private val saveComposerDraftLambda: (ComposerDraft) -> Result<Unit> = { _: ComposerDraft -> Result.success(Unit) },
|
||||
private val loadComposerDraftLambda: () -> Result<ComposerDraft?> = { Result.success<ComposerDraft?>(null) },
|
||||
|
|
@ -203,6 +204,10 @@ class FakeMatrixRoom(
|
|||
pinnedEventsTimelineResult()
|
||||
}
|
||||
|
||||
override suspend fun mediaTimeline(): Result<Timeline> = simulateLongTask {
|
||||
mediaTimelineResult()
|
||||
}
|
||||
|
||||
override suspend fun subscribeToSync() {
|
||||
subscribeToSyncLambda()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue