Update regarding SDK change on verification data

This commit is contained in:
Benoit Marty 2023-12-08 16:36:47 +01:00
parent de9645e514
commit 78ce22d458
8 changed files with 105 additions and 48 deletions

View file

@ -97,7 +97,7 @@ class VerifySelfSessionPresenter @Inject constructor(
is StateMachineState.Verifying.Replying -> Async.Loading() is StateMachineState.Verifying.Replying -> Async.Loading()
else -> Async.Uninitialized else -> Async.Uninitialized
} }
VerifySelfSessionState.VerificationStep.Verifying(machineState.emojis, async) VerifySelfSessionState.VerificationStep.Verifying(machineState.data, async)
} }
StateMachineState.Completed -> { StateMachineState.Completed -> {
@ -116,7 +116,7 @@ class VerifySelfSessionPresenter @Inject constructor(
stateMachine.dispatch(VerifySelfSessionStateMachine.Event.DidStartSasVerification) stateMachine.dispatch(VerifySelfSessionStateMachine.Event.DidStartSasVerification)
} }
is VerificationFlowState.ReceivedVerificationData -> { is VerificationFlowState.ReceivedVerificationData -> {
stateMachine.dispatch(VerifySelfSessionStateMachine.Event.DidReceiveChallenge(verificationAttemptState.emoji)) stateMachine.dispatch(VerifySelfSessionStateMachine.Event.DidReceiveChallenge(verificationAttemptState.data))
} }
VerificationFlowState.Finished -> { VerificationFlowState.Finished -> {
stateMachine.dispatch(VerifySelfSessionStateMachine.Event.DidAcceptChallenge) stateMachine.dispatch(VerifySelfSessionStateMachine.Event.DidAcceptChallenge)

View file

@ -19,7 +19,7 @@ package io.element.android.features.verifysession.impl
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.SessionVerificationData
@Immutable @Immutable
data class VerifySelfSessionState( data class VerifySelfSessionState(
@ -33,7 +33,7 @@ data class VerifySelfSessionState(
data object Canceled : VerificationStep data object Canceled : VerificationStep
data object AwaitingOtherDeviceResponse : VerificationStep data object AwaitingOtherDeviceResponse : VerificationStep
data object Ready : VerificationStep data object Ready : VerificationStep
data class Verifying(val emojiList: List<VerificationEmoji>, val state: Async<Unit>) : VerificationStep data class Verifying(val data: SessionVerificationData, val state: Async<Unit>) : VerificationStep
data object Completed : VerificationStep data object Completed : VerificationStep
} }
} }

View file

@ -20,8 +20,8 @@
package io.element.android.features.verifysession.impl package io.element.android.features.verifysession.impl
import com.freeletics.flowredux.dsl.FlowReduxStateMachine import com.freeletics.flowredux.dsl.FlowReduxStateMachine
import io.element.android.libraries.matrix.api.verification.SessionVerificationData
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import javax.inject.Inject import javax.inject.Inject
import com.freeletics.flowredux.dsl.State as MachineState import com.freeletics.flowredux.dsl.State as MachineState
@ -70,15 +70,15 @@ class VerifySelfSessionStateMachine @Inject constructor(
} }
inState<State.SasVerificationStarted> { inState<State.SasVerificationStarted> {
on { event: Event.DidReceiveChallenge, state: MachineState<State.SasVerificationStarted> -> on { event: Event.DidReceiveChallenge, state: MachineState<State.SasVerificationStarted> ->
state.override { State.Verifying.ChallengeReceived(event.emojis) } state.override { State.Verifying.ChallengeReceived(event.data) }
} }
} }
inState<State.Verifying.ChallengeReceived> { inState<State.Verifying.ChallengeReceived> {
on { _: Event.AcceptChallenge, state: MachineState<State.Verifying.ChallengeReceived> -> on { _: Event.AcceptChallenge, state: MachineState<State.Verifying.ChallengeReceived> ->
state.override { State.Verifying.Replying(state.snapshot.emojis, accept = true) } state.override { State.Verifying.Replying(state.snapshot.data, accept = true) }
} }
on { _: Event.DeclineChallenge, state: MachineState<State.Verifying.ChallengeReceived> -> on { _: Event.DeclineChallenge, state: MachineState<State.Verifying.ChallengeReceived> ->
state.override { State.Verifying.Replying(state.snapshot.emojis, accept = false) } state.override { State.Verifying.Replying(state.snapshot.data, accept = false) }
} }
} }
inState<State.Verifying.Replying> { inState<State.Verifying.Replying> {
@ -139,12 +139,12 @@ class VerifySelfSessionStateMachine @Inject constructor(
/** A SaS verification flow has been started. */ /** A SaS verification flow has been started. */
data object SasVerificationStarted : State data object SasVerificationStarted : State
sealed class Verifying(open val emojis: List<VerificationEmoji>) : State { sealed class Verifying(open val data: SessionVerificationData) : State {
/** Verification accepted and emojis received. */ /** Verification accepted and emojis received. */
data class ChallengeReceived(override val emojis: List<VerificationEmoji>) : Verifying(emojis) data class ChallengeReceived(override val data: SessionVerificationData) : Verifying(data)
/** Replying to a verification challenge. */ /** Replying to a verification challenge. */
data class Replying(override val emojis: List<VerificationEmoji>, val accept: Boolean) : Verifying(emojis) data class Replying(override val data: SessionVerificationData, val accept: Boolean) : Verifying(data)
} }
/** The verification is being canceled. */ /** The verification is being canceled. */
@ -170,8 +170,8 @@ class VerifySelfSessionStateMachine @Inject constructor(
/** Started a SaS verification flow. */ /** Started a SaS verification flow. */
data object DidStartSasVerification : Event data object DidStartSasVerification : Event
/** Has received emojis. */ /** Has received data. */
data class DidReceiveChallenge(val emojis: List<VerificationEmoji>) : Event data class DidReceiveChallenge(val data: SessionVerificationData) : Event
/** Emojis match. */ /** Emojis match. */
data object AcceptChallenge : Event data object AcceptChallenge : Event

View file

@ -18,6 +18,7 @@ package io.element.android.features.verifysession.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.verification.SessionVerificationData
import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.VerificationEmoji
open class VerifySelfSessionStateProvider : PreviewParameterProvider<VerifySelfSessionState> { open class VerifySelfSessionStateProvider : PreviewParameterProvider<VerifySelfSessionState> {
@ -28,10 +29,10 @@ open class VerifySelfSessionStateProvider : PreviewParameterProvider<VerifySelfS
verificationFlowStep = VerifySelfSessionState.VerificationStep.AwaitingOtherDeviceResponse verificationFlowStep = VerifySelfSessionState.VerificationStep.AwaitingOtherDeviceResponse
), ),
aVerifySelfSessionState().copy( aVerifySelfSessionState().copy(
verificationFlowStep = VerifySelfSessionState.VerificationStep.Verifying(aVerificationEmojiList(), Async.Uninitialized) verificationFlowStep = VerifySelfSessionState.VerificationStep.Verifying(aSessionVerificationData(), Async.Uninitialized)
), ),
aVerifySelfSessionState().copy( aVerifySelfSessionState().copy(
verificationFlowStep = VerifySelfSessionState.VerificationStep.Verifying(aVerificationEmojiList(), Async.Loading()) verificationFlowStep = VerifySelfSessionState.VerificationStep.Verifying(aSessionVerificationData(), Async.Loading())
), ),
aVerifySelfSessionState().copy( aVerifySelfSessionState().copy(
verificationFlowStep = VerifySelfSessionState.VerificationStep.Canceled verificationFlowStep = VerifySelfSessionState.VerificationStep.Canceled
@ -43,17 +44,28 @@ open class VerifySelfSessionStateProvider : PreviewParameterProvider<VerifySelfS
) )
} }
fun aVerifySelfSessionState() = VerifySelfSessionState( private fun aSessionVerificationData(
emojiList: List<VerificationEmoji> = aVerificationEmojiList(),
decimals: List<Int> = emptyList(),
): SessionVerificationData {
return if (emojiList.isEmpty()) {
SessionVerificationData.Decimals(decimals)
} else {
SessionVerificationData.Emojis(emojiList)
}
}
private fun aVerifySelfSessionState() = VerifySelfSessionState(
verificationFlowStep = VerifySelfSessionState.VerificationStep.Initial, verificationFlowStep = VerifySelfSessionState.VerificationStep.Initial,
eventSink = {}, eventSink = {},
) )
fun aVerificationEmojiList() = listOf( private fun aVerificationEmojiList() = listOf(
VerificationEmoji(27, "Pizza"), VerificationEmoji(number = 27, emoji = "🍕", description = "Pizza"),
VerificationEmoji(54, "Rocket"), VerificationEmoji(number = 54, emoji = "🚀", description = "Rocket"),
VerificationEmoji(54, "Rocket"), VerificationEmoji(number = 54, emoji = "🚀", description = "Rocket"),
VerificationEmoji(42, "Book"), VerificationEmoji(number = 42, emoji = "📕", description = "Book"),
VerificationEmoji(48, "Hammer"), VerificationEmoji(number = 48, emoji = "🔨", description = "Hammer"),
VerificationEmoji(48, "Hammer"), VerificationEmoji(number = 48, emoji = "🔨", description = "Hammer"),
VerificationEmoji(63, "Pin"), VerificationEmoji(number = 63, emoji = "📌", description = "Pin"),
) )

View file

@ -52,6 +52,7 @@ import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.matrix.api.verification.SessionVerificationData
import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.VerificationEmoji
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep as FlowStep import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep as FlowStep
@ -141,17 +142,22 @@ private fun ContentWaiting(modifier: Modifier = Modifier) {
@Composable @Composable
private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying, modifier: Modifier = Modifier) { private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying, modifier: Modifier = Modifier) {
// We want each row to have up to 4 emojis when (verificationFlowStep.data) {
val rows = verificationFlowStep.emojiList.chunked(4) is SessionVerificationData.Decimals -> Unit // TODO Render decimals
Column(modifier = modifier.fillMaxWidth()) { is SessionVerificationData.Emojis -> {
for ((rowIndex, emojis) in rows.withIndex()) { // We want each row to have up to 4 emojis
// Vertical spacing between rows val rows = verificationFlowStep.data.emojis.chunked(4)
if (rowIndex > 0) { Column(modifier = modifier.fillMaxWidth()) {
Spacer(modifier = Modifier.height(40.dp)) for ((rowIndex, emojis) in rows.withIndex()) {
} // Vertical spacing between rows
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) { if (rowIndex > 0) {
for (emoji in emojis) { Spacer(modifier = Modifier.height(40.dp))
EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp)) }
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
for (emoji in emojis) {
EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp))
}
}
} }
} }
} }
@ -160,7 +166,7 @@ private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying, modifier:
@Composable @Composable
private fun EmojiItemView(emoji: VerificationEmoji, modifier: Modifier = Modifier) { private fun EmojiItemView(emoji: VerificationEmoji, modifier: Modifier = Modifier) {
val emojiResource = emoji.code.toEmojiResource() val emojiResource = emoji.number.toEmojiResource()
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier) { Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier) {
Image( Image(
modifier = Modifier.size(48.dp), modifier = Modifier.size(48.dp),

View file

@ -16,7 +16,24 @@
package io.element.android.libraries.matrix.api.verification package io.element.android.libraries.matrix.api.verification
import androidx.compose.runtime.Immutable
@Immutable
sealed interface SessionVerificationData {
data class Emojis(
// 7 emojis
val emojis: List<VerificationEmoji>,
) : SessionVerificationData
data class Decimals(
// 3 numbers
val decimals: List<Int>,
) : SessionVerificationData
}
// https://spec.matrix.org/unstable/client-server-api/#sas-method-emoji
data class VerificationEmoji( data class VerificationEmoji(
val code: Int, val number: Int,
val name: String, val emoji: String,
val description: String,
) )

View file

@ -101,8 +101,8 @@ sealed interface VerificationFlowState {
/** Short Authentication String (SAS) verification started between the 2 devices. */ /** Short Authentication String (SAS) verification started between the 2 devices. */
data object StartedSasVerification : VerificationFlowState data object StartedSasVerification : VerificationFlowState
/** Verification data for the SAS verification (emojis) received. */ /** Verification data for the SAS verification received. */
data class ReceivedVerificationData(val emoji: ImmutableList<VerificationEmoji>) : VerificationFlowState data class ReceivedVerificationData(val data: SessionVerificationData) : VerificationFlowState
/** Verification completed successfully. */ /** Verification completed successfully. */
data object Finished : VerificationFlowState data object Finished : VerificationFlowState

View file

@ -18,12 +18,12 @@ package io.element.android.libraries.matrix.impl.verification
import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.api.verification.SessionVerificationData
import io.element.android.libraries.matrix.api.verification.SessionVerificationService 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.SessionVerifiedStatus
import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.VerificationEmoji
import io.element.android.libraries.matrix.api.verification.VerificationFlowState import io.element.android.libraries.matrix.api.verification.VerificationFlowState
import io.element.android.libraries.matrix.impl.sync.RustSyncService import io.element.android.libraries.matrix.impl.sync.RustSyncService
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -33,7 +33,8 @@ import kotlinx.coroutines.launch
import org.matrix.rustcomponents.sdk.SessionVerificationController import org.matrix.rustcomponents.sdk.SessionVerificationController
import org.matrix.rustcomponents.sdk.SessionVerificationControllerDelegate import org.matrix.rustcomponents.sdk.SessionVerificationControllerDelegate
import org.matrix.rustcomponents.sdk.SessionVerificationControllerInterface import org.matrix.rustcomponents.sdk.SessionVerificationControllerInterface
import org.matrix.rustcomponents.sdk.SessionVerificationEmoji import org.matrix.rustcomponents.sdk.use
import org.matrix.rustcomponents.sdk.SessionVerificationData as RustSessionVerificationData
class RustSessionVerificationService( class RustSessionVerificationService(
private val syncService: RustSyncService, private val syncService: RustSyncService,
@ -105,12 +106,8 @@ class RustSessionVerificationService(
updateVerificationStatus(isVerified = true) updateVerificationStatus(isVerified = true)
} }
override fun didReceiveVerificationData(data: List<SessionVerificationEmoji>) { override fun didReceiveVerificationData(data: RustSessionVerificationData) {
val emojis = data.map { emoji -> _verificationFlowState.value = VerificationFlowState.ReceivedVerificationData(data.map())
emoji.use { VerificationEmoji(it.code(), it.description()) }
}
.toImmutableList()
_verificationFlowState.value = VerificationFlowState.ReceivedVerificationData(emojis)
} }
// When the actual SAS verification starts // When the actual SAS verification starts
@ -142,3 +139,28 @@ class RustSessionVerificationService(
_sessionVerifiedStatus.value = newValue _sessionVerifiedStatus.value = newValue
} }
} }
private fun RustSessionVerificationData.map(): SessionVerificationData {
return use { sessionVerificationData ->
when (sessionVerificationData) {
is RustSessionVerificationData.Emojis -> {
SessionVerificationData.Emojis(
emojis = sessionVerificationData.emojis.mapIndexed { index, emoji ->
emoji.use { sessionVerificationEmoji ->
VerificationEmoji(
number = sessionVerificationData.indices[index].toInt(),
emoji = sessionVerificationEmoji.symbol(),
description = sessionVerificationEmoji.description(),
)
}
},
)
}
is RustSessionVerificationData.Decimals -> {
SessionVerificationData.Decimals(
decimals = sessionVerificationData.values.map { it.toInt() },
)
}
}
}
}