Merge pull request #2759 from element-hq/feature/fga/permalink_timeline
Permalink timeline
This commit is contained in:
commit
ae8ee8704f
383 changed files with 3579 additions and 1506 deletions
|
|
@ -32,8 +32,8 @@ import io.element.android.libraries.matrix.api.poll.PollKind
|
|||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -98,7 +98,16 @@ interface MatrixRoom : Closeable {
|
|||
|
||||
val syncUpdateFlow: StateFlow<Long>
|
||||
|
||||
val timeline: MatrixTimeline
|
||||
/**
|
||||
* The live timeline of the room. Must be used to send Event to a room.
|
||||
*/
|
||||
val liveTimeline: Timeline
|
||||
|
||||
/**
|
||||
* Create a new timeline, focused on the provided Event.
|
||||
* Should not be used directly, see `TimelineController` to manage the various timelines.
|
||||
*/
|
||||
suspend fun timelineFocusedOnEvent(eventId: EventId): Result<Timeline>
|
||||
|
||||
fun destroy()
|
||||
|
||||
|
|
@ -122,12 +131,6 @@ interface MatrixRoom : Closeable {
|
|||
|
||||
suspend fun sendMessage(body: String, htmlBody: String?, mentions: List<Mention>): Result<Unit>
|
||||
|
||||
suspend fun editMessage(originalEventId: EventId?, transactionId: TransactionId?, body: String, htmlBody: String?, mentions: List<Mention>): Result<Unit>
|
||||
|
||||
suspend fun enterSpecialMode(eventId: EventId?): Result<Unit>
|
||||
|
||||
suspend fun replyMessage(eventId: EventId, body: String, htmlBody: String?, mentions: List<Mention>): Result<Unit>
|
||||
|
||||
suspend fun redactEvent(eventId: EventId, reason: String? = null): Result<Unit>
|
||||
|
||||
suspend fun sendImage(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.room.errors
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
|
||||
sealed class FocusEventException : Exception() {
|
||||
data class InvalidEventId(
|
||||
val eventId: String,
|
||||
val err: String
|
||||
) : FocusEventException()
|
||||
|
||||
data class EventNotFound(
|
||||
val eventId: EventId
|
||||
) : FocusEventException()
|
||||
|
||||
data class Other(
|
||||
val msg: String
|
||||
) : FocusEventException()
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
interface MatrixTimeline : AutoCloseable {
|
||||
data class PaginationState(
|
||||
val isBackPaginating: Boolean,
|
||||
val hasMoreToLoadBackwards: Boolean,
|
||||
val beginningOfRoomReached: Boolean,
|
||||
) {
|
||||
val canBackPaginate = !isBackPaginating && hasMoreToLoadBackwards
|
||||
|
||||
companion object {
|
||||
val Initial = PaginationState(
|
||||
isBackPaginating = false,
|
||||
hasMoreToLoadBackwards = true,
|
||||
beginningOfRoomReached = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val paginationState: StateFlow<PaginationState>
|
||||
val timelineItems: Flow<List<MatrixTimelineItem>>
|
||||
val membershipChangeEventReceived: Flow<Unit>
|
||||
|
||||
suspend fun paginateBackwards(requestSize: Int): Result<Unit>
|
||||
suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result<Unit>
|
||||
suspend fun fetchDetailsForEvent(eventId: EventId): Result<Unit>
|
||||
suspend fun sendReadReceipt(eventId: EventId, receiptType: ReceiptType): Result<Unit>
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
||||
import io.element.android.libraries.matrix.api.media.AudioInfo
|
||||
import io.element.android.libraries.matrix.api.media.FileInfo
|
||||
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||
import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
||||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.Mention
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.io.File
|
||||
|
||||
interface Timeline : AutoCloseable {
|
||||
data class PaginationStatus(
|
||||
val isPaginating: Boolean,
|
||||
val hasMoreToLoad: Boolean,
|
||||
) {
|
||||
val canPaginate: Boolean = !isPaginating && hasMoreToLoad
|
||||
}
|
||||
|
||||
enum class PaginationDirection {
|
||||
BACKWARDS,
|
||||
FORWARDS
|
||||
}
|
||||
|
||||
val membershipChangeEventReceived: Flow<Unit>
|
||||
suspend fun sendReadReceipt(eventId: EventId, receiptType: ReceiptType): Result<Unit>
|
||||
suspend fun paginate(direction: PaginationDirection): Result<Boolean>
|
||||
fun paginationStatus(direction: PaginationDirection): StateFlow<PaginationStatus>
|
||||
val timelineItems: Flow<List<MatrixTimelineItem>>
|
||||
|
||||
suspend fun sendMessage(body: String, htmlBody: String?, mentions: List<Mention>): Result<Unit>
|
||||
|
||||
suspend fun editMessage(originalEventId: EventId?, transactionId: TransactionId?, body: String, htmlBody: String?, mentions: List<Mention>): Result<Unit>
|
||||
|
||||
suspend fun enterSpecialMode(eventId: EventId?): Result<Unit>
|
||||
|
||||
suspend fun replyMessage(eventId: EventId, body: String, htmlBody: String?, mentions: List<Mention>): Result<Unit>
|
||||
|
||||
suspend fun sendImage(
|
||||
file: File,
|
||||
thumbnailFile: File?,
|
||||
imageInfo: ImageInfo,
|
||||
body: String?,
|
||||
formattedBody: String?,
|
||||
progressCallback: ProgressCallback?
|
||||
): Result<MediaUploadHandler>
|
||||
|
||||
suspend fun sendVideo(
|
||||
file: File,
|
||||
thumbnailFile: File?,
|
||||
videoInfo: VideoInfo,
|
||||
body: String?,
|
||||
formattedBody: String?,
|
||||
progressCallback: ProgressCallback?
|
||||
): Result<MediaUploadHandler>
|
||||
|
||||
suspend fun sendAudio(file: File, audioInfo: AudioInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
|
||||
|
||||
suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
|
||||
|
||||
suspend fun toggleReaction(emoji: String, eventId: EventId): Result<Unit>
|
||||
|
||||
suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit>
|
||||
|
||||
suspend fun retrySendMessage(transactionId: TransactionId): Result<Unit>
|
||||
|
||||
suspend fun cancelSend(transactionId: TransactionId): Result<Unit>
|
||||
|
||||
/**
|
||||
* Share a location message in the room.
|
||||
*
|
||||
* @param body A human readable textual representation of the location.
|
||||
* @param geoUri A geo URI (RFC 5870) representing the location e.g. `geo:51.5008,0.1247;u=35`.
|
||||
* Respectively: latitude, longitude, and (optional) uncertainty.
|
||||
* @param description Optional description of the location to display to the user.
|
||||
* @param zoomLevel Optional zoom level to display the map at.
|
||||
* @param assetType Optional type of the location asset.
|
||||
* Set to SENDER if sharing own location. Set to PIN if sharing any location.
|
||||
*/
|
||||
suspend fun sendLocation(
|
||||
body: String,
|
||||
geoUri: String,
|
||||
description: String? = null,
|
||||
zoomLevel: Int? = null,
|
||||
assetType: AssetType? = null,
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Create a poll in the room.
|
||||
*
|
||||
* @param question The question to ask.
|
||||
* @param answers The list of answers.
|
||||
* @param maxSelections The maximum number of answers that can be selected.
|
||||
* @param pollKind The kind of poll to create.
|
||||
*/
|
||||
suspend fun createPoll(
|
||||
question: String,
|
||||
answers: List<String>,
|
||||
maxSelections: Int,
|
||||
pollKind: PollKind,
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Edit a poll in the room.
|
||||
*
|
||||
* @param pollStartId The event ID of the poll start event.
|
||||
* @param question The question to ask.
|
||||
* @param answers The list of answers.
|
||||
* @param maxSelections The maximum number of answers that can be selected.
|
||||
* @param pollKind The kind of poll to create.
|
||||
*/
|
||||
suspend fun editPoll(
|
||||
pollStartId: EventId,
|
||||
question: String,
|
||||
answers: List<String>,
|
||||
maxSelections: Int,
|
||||
pollKind: PollKind,
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Send a response to a poll.
|
||||
*
|
||||
* @param pollStartId The event ID of the poll start event.
|
||||
* @param answers The list of answer ids to send.
|
||||
*/
|
||||
suspend fun sendPollResponse(pollStartId: EventId, answers: List<String>): Result<Unit>
|
||||
|
||||
/**
|
||||
* Ends a poll in the room.
|
||||
*
|
||||
* @param pollStartId The event ID of the poll start event.
|
||||
* @param text Fallback text of the poll end event.
|
||||
*/
|
||||
suspend fun endPoll(pollStartId: EventId, text: String): Result<Unit>
|
||||
|
||||
suspend fun sendVoiceMessage(
|
||||
file: File,
|
||||
audioInfo: AudioInfo,
|
||||
waveform: List<Float>,
|
||||
progressCallback: ProgressCallback?
|
||||
): Result<MediaUploadHandler>
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.timeline
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* This interface defines a way to get the active timeline.
|
||||
* It could be the current room timeline, or a timeline for a specific event.
|
||||
*/
|
||||
interface TimelineProvider {
|
||||
fun activeTimelineFlow(): StateFlow<Timeline>
|
||||
}
|
||||
|
||||
suspend fun TimelineProvider.getActiveTimeline(): Timeline = activeTimelineFlow().first()
|
||||
|
|
@ -26,7 +26,7 @@ sealed interface InReplyTo {
|
|||
data class NotLoaded(val eventId: EventId) : InReplyTo
|
||||
|
||||
/** The event details are pending to be fetched. We should **not** fetch them again. */
|
||||
data object Pending : InReplyTo
|
||||
data class Pending(val eventId: EventId) : InReplyTo
|
||||
|
||||
/** The event details are available. */
|
||||
data class Ready(
|
||||
|
|
@ -44,5 +44,8 @@ sealed interface InReplyTo {
|
|||
* If the reason for the failure is consistent on the server, we'd enter a loop
|
||||
* where we keep trying to fetch the same event.
|
||||
* */
|
||||
data object Error : InReplyTo
|
||||
data class Error(
|
||||
val eventId: EventId,
|
||||
val message: String,
|
||||
) : InReplyTo
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package io.element.android.libraries.matrix.api.timeline.item.virtual
|
||||
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
|
||||
sealed interface VirtualTimelineItem {
|
||||
data class DayDivider(
|
||||
val timestamp: Long
|
||||
|
|
@ -24,4 +26,13 @@ sealed interface VirtualTimelineItem {
|
|||
data object ReadMarker : VirtualTimelineItem
|
||||
|
||||
data object EncryptedHistoryBanner : VirtualTimelineItem
|
||||
|
||||
data object RoomBeginning : VirtualTimelineItem
|
||||
|
||||
data object LastForwardIndicator : VirtualTimelineItem
|
||||
|
||||
data class LoadingIndicator(
|
||||
val direction: Timeline.PaginationDirection,
|
||||
val timestamp: Long,
|
||||
) : VirtualTimelineItem
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue