Merge branch 'develop' into feature/bma/dataObject

This commit is contained in:
Benoit Marty 2023-08-28 10:56:02 +02:00 committed by GitHub
commit 1a6376e723
129 changed files with 2140 additions and 487 deletions

View file

@ -20,5 +20,8 @@ enum class PollKind {
Disclosed,
/** Results should be only revealed when the poll is ended. */
Undisclosed
Undisclosed,
}
val PollKind.isDisclosed: Boolean
get() = this == PollKind.Disclosed

View file

@ -27,6 +27,7 @@ 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.location.AssetType
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
import kotlinx.coroutines.flow.StateFlow
@ -141,6 +142,21 @@ interface MatrixRoom : Closeable {
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>
override fun close() = destroy()
}

View file

@ -16,6 +16,7 @@
package io.element.android.libraries.matrix.api.verification
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
interface SessionVerificationService {
@ -37,6 +38,11 @@ interface SessionVerificationService {
*/
val sessionVerifiedStatus: StateFlow<SessionVerifiedStatus>
/**
* Returns whether the current session needs to be verified and the SDK is ready to start the verification.
*/
val canVerifySessionFlow: Flow<Boolean>
/**
* Request verification of the current session.
*/

View file

@ -35,7 +35,6 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.awaitLoaded
import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
@ -93,8 +92,8 @@ class RustMatrixClient constructor(
private val innerRoomListService = syncService.roomListService()
private val sessionDispatcher = dispatchers.io.limitedParallelism(64)
private val sessionCoroutineScope = appCoroutineScope.childScope(dispatchers.main, "Session-${sessionId}")
private val verificationService = RustSessionVerificationService()
private val rustSyncService = RustSyncService(syncService, sessionCoroutineScope)
private val verificationService = RustSessionVerificationService(rustSyncService)
private val pushersService = RustPushersService(
client = client,
dispatchers = dispatchers,
@ -149,13 +148,11 @@ class RustMatrixClient constructor(
init {
client.setDelegate(clientDelegate)
rustSyncService.syncState
.onEach { syncState ->
if (syncState == SyncState.Running) {
onSlidingSyncUpdate()
}
roomListService.state.onEach { state ->
if (state == RoomListService.State.Running) {
setupVerificationControllerIfNeeded()
}
.launchIn(sessionCoroutineScope)
}.launchIn(sessionCoroutineScope)
}
override suspend fun getRoom(roomId: RoomId): MatrixRoom? = withContext(sessionDispatcher) {
@ -338,8 +335,8 @@ class RustMatrixClient constructor(
}
}
private fun onSlidingSyncUpdate() {
if (!verificationService.isReady.value) {
private fun setupVerificationControllerIfNeeded() {
if (verificationService.verificationController == null) {
try {
verificationService.verificationController = client.getSessionVerificationController()
} catch (e: Throwable) {

View file

@ -23,3 +23,8 @@ fun RustPollKind.map(): PollKind = when (this) {
RustPollKind.DISCLOSED -> PollKind.Disclosed
RustPollKind.UNDISCLOSED -> PollKind.Undisclosed
}
fun PollKind.toInner(): RustPollKind = when (this) {
PollKind.Disclosed -> RustPollKind.DISCLOSED
PollKind.Undisclosed -> RustPollKind.UNDISCLOSED
}

View file

@ -30,6 +30,7 @@ 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.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.MessageEventType
@ -41,6 +42,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventType
import io.element.android.libraries.matrix.impl.core.toProgressWatcher
import io.element.android.libraries.matrix.impl.media.MediaUploadHandlerImpl
import io.element.android.libraries.matrix.impl.media.map
import io.element.android.libraries.matrix.impl.poll.toInner
import io.element.android.libraries.matrix.impl.room.location.toInner
import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline
import io.element.android.libraries.matrix.impl.util.destroyAll
@ -378,7 +380,24 @@ class RustMatrixRoom(
description = description,
zoomLevel = zoomLevel?.toUByte(),
assetType = assetType?.toInner(),
txnId = genTransactionId()
txnId = genTransactionId(),
)
}
}
override suspend fun createPoll(
question: String,
answers: List<String>,
maxSelections: Int,
pollKind: PollKind,
): Result<Unit> = withContext(roomDispatcher) {
runCatching {
innerRoom.createPoll(
question = question,
answers = answers,
maxSelections = maxSelections.toUByte(),
pollKind = pollKind.toInner(),
txnId = genTransactionId(),
)
}
}

View file

@ -17,20 +17,25 @@
package io.element.android.libraries.matrix.impl.verification
import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
import io.element.android.libraries.matrix.impl.sync.RustSyncService
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import org.matrix.rustcomponents.sdk.SessionVerificationController
import org.matrix.rustcomponents.sdk.SessionVerificationControllerDelegate
import org.matrix.rustcomponents.sdk.SessionVerificationControllerInterface
import org.matrix.rustcomponents.sdk.SessionVerificationEmoji
import javax.inject.Inject
class RustSessionVerificationService @Inject constructor() : SessionVerificationService, SessionVerificationControllerDelegate {
class RustSessionVerificationService @Inject constructor(
private val syncService: RustSyncService,
) : SessionVerificationService, SessionVerificationControllerDelegate {
var verificationController: SessionVerificationControllerInterface? = null
set(value) {
@ -52,6 +57,10 @@ class RustSessionVerificationService @Inject constructor() : SessionVerification
private val _sessionVerifiedStatus = MutableStateFlow<SessionVerifiedStatus>(SessionVerifiedStatus.Unknown)
override val sessionVerifiedStatus: StateFlow<SessionVerifiedStatus> = _sessionVerifiedStatus.asStateFlow()
override val canVerifySessionFlow = combine(sessionVerifiedStatus, syncService.syncState) { verificationStatus, syncState ->
syncState == SyncState.Running && verificationStatus == SessionVerifiedStatus.NotVerified
}
override suspend fun requestVerification() = tryOrFail {
verificationController?.requestVerification()
}

View file

@ -27,6 +27,7 @@ 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.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.MessageEventType
@ -83,6 +84,7 @@ class FakeMatrixRoom(
private var forwardEventResult = Result.success(Unit)
private var reportContentResult = Result.success(Unit)
private var sendLocationResult = Result.success(Unit)
private var createPollResult = Result.success(Unit)
private var progressCallbackValues = emptyList<Pair<Long, Long>>()
val editMessageCalls = mutableListOf<String>()
@ -104,6 +106,9 @@ class FakeMatrixRoom(
private val _sentLocations = mutableListOf<SendLocationInvocation>()
val sentLocations: List<SendLocationInvocation> = _sentLocations
private val _createPollInvocations = mutableListOf<CreatePollInvocation>()
val createPollInvocations: List<CreatePollInvocation> = _createPollInvocations
var invitedUserId: UserId? = null
private set
@ -305,6 +310,16 @@ class FakeMatrixRoom(
return sendLocationResult
}
override suspend fun createPoll(
question: String,
answers: List<String>,
maxSelections: Int,
pollKind: PollKind
): Result<Unit> = simulateLongTask {
_createPollInvocations.add(CreatePollInvocation(question, answers, maxSelections, pollKind))
return createPollResult
}
fun givenLeaveRoomError(throwable: Throwable?) {
this.leaveRoomError = throwable
}
@ -397,6 +412,10 @@ class FakeMatrixRoom(
sendLocationResult = result
}
fun givenCreatePollResult(result: Result<Unit>) {
createPollResult = result
}
fun givenProgressCallbackValues(values: List<Pair<Long, Long>>) {
progressCallbackValues = values
}
@ -409,3 +428,10 @@ data class SendLocationInvocation(
val zoomLevel: Int?,
val assetType: AssetType?,
)
data class CreatePollInvocation(
val question: String,
val answers: List<String>,
val maxSelections: Int,
val pollKind: PollKind,
)

View file

@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.verification.SessionVerificationS
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -27,13 +28,13 @@ class FakeSessionVerificationService : SessionVerificationService {
private val _isReady = MutableStateFlow(false)
private val _sessionVerifiedStatus = MutableStateFlow<SessionVerifiedStatus>(SessionVerifiedStatus.Unknown)
private var _verificationFlowState = MutableStateFlow<VerificationFlowState>(VerificationFlowState.Initial)
private var _canVerifySessionFlow = MutableStateFlow(true)
private var emojiList = emptyList<VerificationEmoji>()
var shouldFail = false
override val verificationFlowState: StateFlow<VerificationFlowState>
get() = _verificationFlowState
override val verificationFlowState: StateFlow<VerificationFlowState> =_verificationFlowState
override val sessionVerifiedStatus: StateFlow<SessionVerifiedStatus> = _sessionVerifiedStatus
override val canVerifySessionFlow: Flow<Boolean> = _canVerifySessionFlow
override val isReady: StateFlow<Boolean> = _isReady
@ -77,6 +78,10 @@ class FakeSessionVerificationService : SessionVerificationService {
_verificationFlowState.value = state
}
fun givenCanVerifySession(canVerify: Boolean) {
_canVerifySessionFlow.value = canVerify
}
fun givenIsReady(value: Boolean) {
_isReady.value = value
}