happy path qr kotlin verif
This commit is contained in:
parent
cf366f7a9c
commit
5c82bdba38
@ -40,7 +40,6 @@ import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
|
|||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.getRoom
|
import org.matrix.android.sdk.api.session.getRoom
|
||||||
|
@ -561,7 +561,6 @@ class SASTest : InstrumentedTest {
|
|||||||
|
|
||||||
val requestID = req.transactionId
|
val requestID = req.transactionId
|
||||||
|
|
||||||
|
|
||||||
Log.v("TEST", "== requestID is $requestID")
|
Log.v("TEST", "== requestID is $requestID")
|
||||||
|
|
||||||
testHelper.retryPeriodically {
|
testHelper.retryPeriodically {
|
||||||
|
@ -1233,7 +1233,7 @@ internal class DefaultVerificationService @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun reciprocateQRVerification(otherUserId: String, requestId: String, scannedData: String): String? {
|
override suspend fun reciprocateQRVerification(otherUserId: String, requestId: String, scannedData: String): String? {
|
||||||
val deferred = CompletableDeferred<VerificationTransaction>()
|
val deferred = CompletableDeferred<VerificationTransaction?>()
|
||||||
stateMachine.send(
|
stateMachine.send(
|
||||||
VerificationIntent.ActionReciprocateQrVerification(
|
VerificationIntent.ActionReciprocateQrVerification(
|
||||||
otherUserId = otherUserId,
|
otherUserId = otherUserId,
|
||||||
@ -1242,7 +1242,7 @@ internal class DefaultVerificationService @Inject constructor(
|
|||||||
deferred = deferred
|
deferred = deferred
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return deferred.await().transactionId
|
return deferred.await()?.transactionId
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun requestKeyVerificationInDMs(
|
override suspend fun requestKeyVerificationInDMs(
|
||||||
|
@ -16,41 +16,67 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto.verification
|
package org.matrix.android.sdk.internal.crypto.verification
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.QRCodeVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeData
|
||||||
|
import org.matrix.android.sdk.internal.crypto.verification.qrcode.toEncodedString
|
||||||
|
|
||||||
class KotlinQRVerification(
|
internal class KotlinQRVerification(
|
||||||
override val qrCodeText: String?,
|
private val channel: Channel<VerificationIntent>,
|
||||||
override val state: VerificationTxState,
|
var qrCodeData: QrCodeData?,
|
||||||
override val method: VerificationMethod,
|
override val method: VerificationMethod,
|
||||||
override val transactionId: String,
|
override val transactionId: String,
|
||||||
override val otherUserId: String,
|
override val otherUserId: String,
|
||||||
override val otherDeviceId: String?,
|
override val otherDeviceId: String?,
|
||||||
override val isIncoming: Boolean) : QrCodeVerificationTransaction {
|
override val isIncoming: Boolean,
|
||||||
|
var state: QRCodeVerificationState,
|
||||||
|
val isToDevice: Boolean
|
||||||
|
) : QrCodeVerificationTransaction {
|
||||||
|
|
||||||
override suspend fun userHasScannedOtherQrCode(otherQrCodeText: String) {
|
override fun state() = state
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
override val qrCodeText: String?
|
||||||
|
get() = qrCodeData?.toEncodedString()
|
||||||
|
//
|
||||||
|
// var userMSKKeyToTrust: String? = null
|
||||||
|
// var deviceKeysToTrust = mutableListOf<String>()
|
||||||
|
|
||||||
|
// override suspend fun userHasScannedOtherQrCode(otherQrCodeText: String) {
|
||||||
|
// TODO("Not yet implemented")
|
||||||
|
// }
|
||||||
|
|
||||||
override suspend fun otherUserScannedMyQrCode() {
|
override suspend fun otherUserScannedMyQrCode() {
|
||||||
TODO("Not yet implemented")
|
val deferred = CompletableDeferred<Unit>()
|
||||||
|
channel.send(
|
||||||
|
VerificationIntent.ActionConfirmCodeWasScanned(otherUserId, transactionId, deferred)
|
||||||
|
)
|
||||||
|
deferred.await()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun otherUserDidNotScannedMyQrCode() {
|
override suspend fun otherUserDidNotScannedMyQrCode() {
|
||||||
TODO("Not yet implemented")
|
val deferred = CompletableDeferred<Unit>()
|
||||||
|
channel.send(
|
||||||
|
// TODO what cancel code??
|
||||||
|
VerificationIntent.ActionCancel(transactionId, deferred)
|
||||||
|
)
|
||||||
|
deferred.await()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun cancel() {
|
override suspend fun cancel() {
|
||||||
TODO("Not yet implemented")
|
cancel(CancelCode.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun cancel(code: CancelCode) {
|
override suspend fun cancel(code: CancelCode) {
|
||||||
TODO("Not yet implemented")
|
val deferred = CompletableDeferred<Unit>()
|
||||||
|
channel.send(
|
||||||
|
VerificationIntent.ActionCancel(transactionId, deferred)
|
||||||
|
)
|
||||||
|
deferred.await()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isToDeviceTransport(): Boolean {
|
override fun isToDeviceTransport() = isToDevice
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
|||||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasMode
|
import org.matrix.android.sdk.api.session.crypto.verification.SasMode
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.SasTransactionState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.KEY_AGREEMENT_V1
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.KEY_AGREEMENT_V1
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.KEY_AGREEMENT_V2
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.KEY_AGREEMENT_V2
|
||||||
@ -32,7 +33,6 @@ import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTra
|
|||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.SAS_MAC_SHA256
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.SAS_MAC_SHA256
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.SAS_MAC_SHA256_LONGKDF
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction.Companion.SAS_MAC_SHA256_LONGKDF
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.RelationType
|
import org.matrix.android.sdk.api.session.events.model.RelationType
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationAcceptContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationAcceptContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationKeyContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationKeyContent
|
||||||
@ -50,9 +50,8 @@ import org.matrix.olm.OlmSAS
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
internal class SasV1Transaction(
|
internal class KotlinSasTransaction(
|
||||||
private val channel: Channel<VerificationIntent>,
|
private val channel: Channel<VerificationIntent>,
|
||||||
override var state: VerificationTxState,
|
|
||||||
override val transactionId: String,
|
override val transactionId: String,
|
||||||
override val otherUserId: String,
|
override val otherUserId: String,
|
||||||
private val myUserId: String,
|
private val myUserId: String,
|
||||||
@ -63,6 +62,7 @@ internal class SasV1Transaction(
|
|||||||
override val isIncoming: Boolean,
|
override val isIncoming: Boolean,
|
||||||
val startReq: ValidVerificationInfoStart.SasVerificationInfoStart? = null,
|
val startReq: ValidVerificationInfoStart.SasVerificationInfoStart? = null,
|
||||||
val isToDevice: Boolean,
|
val isToDevice: Boolean,
|
||||||
|
var state: SasTransactionState
|
||||||
) : SasVerificationTransaction {
|
) : SasVerificationTransaction {
|
||||||
|
|
||||||
override val method: VerificationMethod
|
override val method: VerificationMethod
|
||||||
@ -207,6 +207,8 @@ internal class SasV1Transaction(
|
|||||||
var myMac: ValidVerificationInfoMac? = null
|
var myMac: ValidVerificationInfoMac? = null
|
||||||
var theirMac: ValidVerificationInfoMac? = null
|
var theirMac: ValidVerificationInfoMac? = null
|
||||||
|
|
||||||
|
override fun state() = this.state
|
||||||
|
|
||||||
override fun supportsEmoji(): Boolean {
|
override fun supportsEmoji(): Boolean {
|
||||||
return accepted?.shortAuthenticationStrings?.contains(SasMode.EMOJI) == true
|
return accepted?.shortAuthenticationStrings?.contains(SasMode.EMOJI) == true
|
||||||
}
|
}
|
@ -27,19 +27,23 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
|
|||||||
import org.matrix.android.sdk.api.logger.LoggerTag
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
|
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.SendToDeviceObject
|
import org.matrix.android.sdk.api.session.crypto.model.SendToDeviceObject
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.QRCodeVerificationState
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.SasTransactionState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
|
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
||||||
import org.matrix.android.sdk.api.session.events.model.Content
|
import org.matrix.android.sdk.api.session.events.model.Content
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
@ -53,6 +57,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageVerification
|
|||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationStartContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationStartContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||||
|
import org.matrix.android.sdk.internal.crypto.SecretShareManager
|
||||||
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
|
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationCancel
|
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationCancel
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationDone
|
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationDone
|
||||||
@ -94,7 +99,8 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||||
private val sendToDeviceTask: SendToDeviceTask,
|
private val sendToDeviceTask: SendToDeviceTask,
|
||||||
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
||||||
private val crossSigningService: dagger.Lazy<CrossSigningService>
|
private val crossSigningService: dagger.Lazy<CrossSigningService>,
|
||||||
|
private val secretShareManager: SecretShareManager,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
@ -121,6 +127,34 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
channel.send(intent)
|
channel.send(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun withMatchingRequest(
|
||||||
|
otherUserId: String,
|
||||||
|
requestId: String,
|
||||||
|
block: suspend ((KotlinVerificationRequest) -> Unit)
|
||||||
|
) {
|
||||||
|
val matchingRequest = pendingRequests[otherUserId]
|
||||||
|
?.firstOrNull { it.requestId == requestId }
|
||||||
|
?: return Unit.also {
|
||||||
|
// Receive a transaction event with no matching request.. should ignore.
|
||||||
|
// Not supported any more to do raw start
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.v("[${myUserId.take(8)}] request $requestId not found!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingRequest.state == EVerificationState.HandledByOtherSession) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.v("[${myUserId.take(8)}] ignore transaction event for $requestId handled by other")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingRequest.isFinished()) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.v("[${myUserId.take(8)}] ignore transaction event for $requestId for finished request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
block.invoke(matchingRequest)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun withMatchingRequest(
|
private suspend fun withMatchingRequest(
|
||||||
otherUserId: String,
|
otherUserId: String,
|
||||||
requestId: String,
|
requestId: String,
|
||||||
@ -202,7 +236,13 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
handleSasStart(msg)
|
handleSasStart(msg)
|
||||||
}
|
}
|
||||||
is VerificationIntent.ActionReciprocateQrVerification -> {
|
is VerificationIntent.ActionReciprocateQrVerification -> {
|
||||||
handleReciprocateQR(msg)
|
handleActionReciprocateQR(msg)
|
||||||
|
}
|
||||||
|
is VerificationIntent.ActionConfirmCodeWasScanned -> {
|
||||||
|
withMatchingRequest(msg.otherUserId, msg.requestId) {
|
||||||
|
handleActionQRScanConfirmed(it)
|
||||||
|
}
|
||||||
|
msg.deferred.complete(Unit)
|
||||||
}
|
}
|
||||||
is VerificationIntent.OnStartReceived -> {
|
is VerificationIntent.OnStartReceived -> {
|
||||||
onStartReceived(msg)
|
onStartReceived(msg)
|
||||||
@ -277,14 +317,15 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
request.state = EVerificationState.Cancelled
|
request.state = EVerificationState.Cancelled
|
||||||
val cancelCode = safeValueOf(msg.validCancel.code)
|
val cancelCode = safeValueOf(msg.validCancel.code)
|
||||||
request.cancelCode = cancelCode
|
request.cancelCode = cancelCode
|
||||||
val existingTx = txMap[msg.fromUser]?.get(msg.validCancel.transactionId)
|
// TODO or QR
|
||||||
|
val existingTx: KotlinSasTransaction? =
|
||||||
|
getExistingTransaction(msg.validCancel.transactionId) // txMap[msg.fromUser]?.get(msg.validCancel.transactionId)
|
||||||
if (existingTx != null) {
|
if (existingTx != null) {
|
||||||
existingTx.state = VerificationTxState.Cancelled(cancelCode, false)
|
existingTx.state = SasTransactionState.Cancelled(cancelCode, false)
|
||||||
txMap[msg.fromUser]?.remove(msg.validCancel.transactionId)
|
txMap[msg.fromUser]?.remove(msg.validCancel.transactionId)
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existingTx))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existingTx))
|
||||||
}
|
}
|
||||||
eventFlow.emit(VerificationEvent.RequestUpdated(request.toPendingVerificationRequest()))
|
eventFlow.emit(VerificationEvent.RequestUpdated(request.toPendingVerificationRequest()))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VerificationIntent.OnReadyByAnotherOfMySessionReceived -> {
|
is VerificationIntent.OnReadyByAnotherOfMySessionReceived -> {
|
||||||
@ -358,6 +399,27 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleReceiveStartForQR(request: KotlinVerificationRequest, reciprocate: ValidVerificationInfoStart.ReciprocateVerificationInfoStart) {
|
private suspend fun handleReceiveStartForQR(request: KotlinVerificationRequest, reciprocate: ValidVerificationInfoStart.ReciprocateVerificationInfoStart) {
|
||||||
|
// Ok so the other did scan our code
|
||||||
|
val ourSecret = request.qrCodeData?.sharedSecret
|
||||||
|
if (ourSecret != reciprocate.sharedSecret) {
|
||||||
|
// something went wrong
|
||||||
|
cancelRequest(request, CancelCode.MismatchedKeys)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The secret matches, we need manual action to confirm that it was scan
|
||||||
|
val tx = KotlinQRVerification(
|
||||||
|
channel = this.channel,
|
||||||
|
state = QRCodeVerificationState.WaitingForScanConfirmation,
|
||||||
|
qrCodeData = request.qrCodeData,
|
||||||
|
method = VerificationMethod.QR_CODE_SCAN,
|
||||||
|
transactionId = request.requestId,
|
||||||
|
otherUserId = request.otherUserId,
|
||||||
|
otherDeviceId = request.otherDeviceId(),
|
||||||
|
isIncoming = false,
|
||||||
|
isToDevice = request.roomId == null
|
||||||
|
)
|
||||||
|
addTransaction(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleReceiveStartForSas(
|
private suspend fun handleReceiveStartForSas(
|
||||||
@ -372,7 +434,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
// and the other m.key.verification.start event is ignored.
|
// and the other m.key.verification.start event is ignored.
|
||||||
// So let's check if I already send a start?
|
// So let's check if I already send a start?
|
||||||
val requestId = msg.validVerificationInfoStart.transactionId
|
val requestId = msg.validVerificationInfoStart.transactionId
|
||||||
val existing = getExistingTransaction(msg.fromUser, requestId)
|
val existing: KotlinSasTransaction? = getExistingTransaction(msg.fromUser, requestId)
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
Timber.tag(loggerTag.value)
|
Timber.tag(loggerTag.value)
|
||||||
.v("[${myUserId.take(8)}] No existing Sas transaction for ${request.requestId}")
|
.v("[${myUserId.take(8)}] No existing Sas transaction for ${request.requestId}")
|
||||||
@ -380,23 +442,6 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val sasTx = SasV1Transaction(
|
|
||||||
channel = channel,
|
|
||||||
transactionId = requestId,
|
|
||||||
state = VerificationTxState.None,
|
|
||||||
otherUserId = request.otherUserId,
|
|
||||||
myUserId = myUserId,
|
|
||||||
myTrustedMSK = cryptoStore.getMyCrossSigningInfo()
|
|
||||||
?.takeIf { it.isTrusted() }
|
|
||||||
?.masterKey()
|
|
||||||
?.unpaddedBase64PublicKey,
|
|
||||||
otherDeviceId = request.otherDeviceId(),
|
|
||||||
myDeviceId = cryptoStore.getDeviceId(),
|
|
||||||
myDeviceFingerprint = cryptoStore.getUserDevice(myUserId, cryptoStore.getDeviceId())?.fingerprint().orEmpty(),
|
|
||||||
startReq = sasStart,
|
|
||||||
isIncoming = true,
|
|
||||||
isToDevice = msg.viaRoom == null
|
|
||||||
)
|
|
||||||
// we accept with the agreement methods
|
// we accept with the agreement methods
|
||||||
// Select a key agreement protocol, a hash algorithm, a message authentication code,
|
// Select a key agreement protocol, a hash algorithm, a message authentication code,
|
||||||
// and short authentication string methods out of the lists given in requester's message.
|
// and short authentication string methods out of the lists given in requester's message.
|
||||||
@ -440,11 +485,28 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
cancelRequest(request, CancelCode.UserError)
|
cancelRequest(request, CancelCode.UserError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val sasTx = KotlinSasTransaction(
|
||||||
|
channel = channel,
|
||||||
|
transactionId = requestId,
|
||||||
|
state = SasTransactionState.None,
|
||||||
|
otherUserId = request.otherUserId,
|
||||||
|
myUserId = myUserId,
|
||||||
|
myTrustedMSK = cryptoStore.getMyCrossSigningInfo()
|
||||||
|
?.takeIf { it.isTrusted() }
|
||||||
|
?.masterKey()
|
||||||
|
?.unpaddedBase64PublicKey,
|
||||||
|
otherDeviceId = request.otherDeviceId(),
|
||||||
|
myDeviceId = cryptoStore.getDeviceId(),
|
||||||
|
myDeviceFingerprint = cryptoStore.getUserDevice(myUserId, cryptoStore.getDeviceId())?.fingerprint().orEmpty(),
|
||||||
|
startReq = sasStart,
|
||||||
|
isIncoming = true,
|
||||||
|
isToDevice = msg.viaRoom == null,
|
||||||
|
)
|
||||||
|
|
||||||
val concat = sasTx.getSAS().publicKey + sasStart.canonicalJson
|
val concat = sasTx.getSAS().publicKey + sasStart.canonicalJson
|
||||||
val commitment = hashUsingAgreedHashMethod(agreedHash, concat)
|
val commitment = hashUsingAgreedHashMethod(agreedHash, concat)
|
||||||
|
|
||||||
val accept = SasV1Transaction.sasAccept(
|
val accept = KotlinSasTransaction.sasAccept(
|
||||||
inRoom = request.roomId != null,
|
inRoom = request.roomId != null,
|
||||||
requestId = requestId,
|
requestId = requestId,
|
||||||
keyAgreementProtocol = agreedProtocol,
|
keyAgreementProtocol = agreedProtocol,
|
||||||
@ -464,7 +526,6 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sasTx.accepted = accept.asValidObject()
|
sasTx.accepted = accept.asValidObject()
|
||||||
sasTx.state = VerificationTxState.SasAccepted
|
|
||||||
|
|
||||||
addTransaction(sasTx)
|
addTransaction(sasTx)
|
||||||
}
|
}
|
||||||
@ -472,13 +533,13 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
private suspend fun handleReceiveAccept(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnAcceptReceived) {
|
private suspend fun handleReceiveAccept(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnAcceptReceived) {
|
||||||
val requestId = msg.validAccept.transactionId
|
val requestId = msg.validAccept.transactionId
|
||||||
|
|
||||||
val existing = getExistingTransaction(msg.fromUser, requestId)
|
val existing: KotlinSasTransaction = getExistingTransaction(msg.fromUser, requestId)
|
||||||
?: return Unit.also {
|
?: return Unit.also {
|
||||||
Timber.v("on accept received in room ${msg.viaRoom} for verification id:${requestId} in room ${matchingRequest.roomId}")
|
Timber.v("on accept received in room ${msg.viaRoom} for verification id:${requestId} in room ${matchingRequest.roomId}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Existing should be in
|
// Existing should be in
|
||||||
if (existing.state != VerificationTxState.SasStarted) {
|
if (existing.state != SasTransactionState.SasStarted) {
|
||||||
// it's a wrong state should cancel?
|
// it's a wrong state should cancel?
|
||||||
// TODO cancel
|
// TODO cancel
|
||||||
}
|
}
|
||||||
@ -501,10 +562,9 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
// and replies with a to_device message with type set to “m.key.verification.key”, sending Alice’s public key QA
|
// and replies with a to_device message with type set to “m.key.verification.key”, sending Alice’s public key QA
|
||||||
val pubKey = existing.getSAS().publicKey
|
val pubKey = existing.getSAS().publicKey
|
||||||
|
|
||||||
val keyMessage = SasV1Transaction.sasKeyMessage(matchingRequest.roomId != null, requestId, pubKey)
|
val keyMessage = KotlinSasTransaction.sasKeyMessage(matchingRequest.roomId != null, requestId, pubKey)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (BuildConfig.LOG_PRIVATE_DATA) {
|
if (BuildConfig.LOG_PRIVATE_DATA) {
|
||||||
Timber.tag(loggerTag.value)
|
Timber.tag(loggerTag.value)
|
||||||
.v("[${myUserId.take(8)}]: Sending my key $pubKey")
|
.v("[${myUserId.take(8)}]: Sending my key $pubKey")
|
||||||
@ -515,7 +575,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
keyMessage,
|
keyMessage,
|
||||||
)
|
)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
existing.state = VerificationTxState.Cancelled(CancelCode.UserError, true)
|
existing.state = SasTransactionState.Cancelled(CancelCode.UserError, true)
|
||||||
matchingRequest.cancelCode = CancelCode.UserError
|
matchingRequest.cancelCode = CancelCode.UserError
|
||||||
matchingRequest.state = EVerificationState.Cancelled
|
matchingRequest.state = EVerificationState.Cancelled
|
||||||
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||||
@ -523,7 +583,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
existing.accepted = accept
|
existing.accepted = accept
|
||||||
existing.state = VerificationTxState.SasKeySent
|
existing.state = SasTransactionState.SasKeySent
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,13 +605,13 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
msg.deferred.completeExceptionally(java.lang.IllegalArgumentException("Failed to find other device Id"))
|
msg.deferred.completeExceptionally(java.lang.IllegalArgumentException("Failed to find other device Id"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val existingTransaction = getExistingTransaction(msg.otherUserId, msg.requestId)
|
val existingTransaction = getExistingTransaction<VerificationTransaction>(msg.otherUserId, msg.requestId)
|
||||||
if (existingTransaction is SasVerificationTransaction) {
|
if (existingTransaction is SasVerificationTransaction) {
|
||||||
// there is already an existing transaction??
|
// there is already an existing transaction??
|
||||||
msg.deferred.completeExceptionally(IllegalStateException("Already started"))
|
msg.deferred.completeExceptionally(IllegalStateException("Already started"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val startMessage = SasV1Transaction.sasStart(
|
val startMessage = KotlinSasTransaction.sasStart(
|
||||||
inRoom = matchingRequest.roomId != null,
|
inRoom = matchingRequest.roomId != null,
|
||||||
fromDevice = cryptoStore.getDeviceId(),
|
fromDevice = cryptoStore.getDeviceId(),
|
||||||
requestId = msg.requestId
|
requestId = msg.requestId
|
||||||
@ -564,10 +624,10 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// should check if already one (and cancel it)
|
// should check if already one (and cancel it)
|
||||||
val tx = SasV1Transaction(
|
val tx = KotlinSasTransaction(
|
||||||
channel = channel,
|
channel = channel,
|
||||||
transactionId = msg.requestId,
|
transactionId = msg.requestId,
|
||||||
state = VerificationTxState.SasStarted,
|
state = SasTransactionState.SasStarted,
|
||||||
otherUserId = msg.otherUserId,
|
otherUserId = msg.otherUserId,
|
||||||
myUserId = myUserId,
|
myUserId = myUserId,
|
||||||
myTrustedMSK = cryptoStore.getMyCrossSigningInfo()
|
myTrustedMSK = cryptoStore.getMyCrossSigningInfo()
|
||||||
@ -589,16 +649,22 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
msg.deferred.complete(tx)
|
msg.deferred.complete(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleReciprocateQR(msg: VerificationIntent.ActionReciprocateQrVerification) {
|
private suspend fun handleActionReciprocateQR(msg: VerificationIntent.ActionReciprocateQrVerification) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] handle reciprocate for ${msg.requestId}")
|
||||||
val matchingRequest = pendingRequests
|
val matchingRequest = pendingRequests
|
||||||
.flatMap { entry ->
|
.flatMap { entry ->
|
||||||
entry.value.filter { it.requestId == msg.requestId }
|
entry.value.filter { it.requestId == msg.requestId }
|
||||||
}.firstOrNull()
|
}.firstOrNull()
|
||||||
?: return Unit.also {
|
?: return Unit.also {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] No matching request, abort ${msg.requestId}")
|
||||||
msg.deferred.completeExceptionally(java.lang.IllegalArgumentException("Unknown request"))
|
msg.deferred.completeExceptionally(java.lang.IllegalArgumentException("Unknown request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchingRequest.state != EVerificationState.Ready) {
|
if (matchingRequest.state != EVerificationState.Ready) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] Can't start if not ready, abort ${msg.requestId}")
|
||||||
msg.deferred.completeExceptionally(java.lang.IllegalStateException("Can't start a non ready request"))
|
msg.deferred.completeExceptionally(java.lang.IllegalStateException("Can't start a non ready request"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -607,21 +673,24 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
msg.deferred.completeExceptionally(java.lang.IllegalArgumentException("Failed to find other device Id"))
|
msg.deferred.completeExceptionally(java.lang.IllegalArgumentException("Failed to find other device Id"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val existingTransaction = getExistingTransaction(msg.otherUserId, msg.requestId)
|
val existingTransaction = getExistingTransaction<VerificationTransaction>(msg.otherUserId, msg.requestId)
|
||||||
// what if there is an existing??
|
// what if there is an existing??
|
||||||
if (existingTransaction != null) {
|
if (existingTransaction != null) {
|
||||||
// cancel or replace??
|
// cancel or replace??
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.w("[${myUserId.take(8)}] There is already a started transaction for request ${msg.requestId}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val myMasterKey = crossSigningService.get()
|
val myMasterKey = crossSigningService.get()
|
||||||
.getUserCrossSigningKeys(myUserId)?.masterKey()?.unpaddedBase64PublicKey
|
.getUserCrossSigningKeys(myUserId)?.masterKey()?.unpaddedBase64PublicKey
|
||||||
var canTrustOtherUserMasterKey = false
|
|
||||||
|
|
||||||
// Check the other device view of my MSK
|
// Check the other device view of my MSK
|
||||||
val otherQrCodeData = msg.scannedData.toQrCodeData()
|
val otherQrCodeData = msg.scannedData.toQrCodeData()
|
||||||
when (otherQrCodeData) {
|
when (otherQrCodeData) {
|
||||||
null -> {
|
null -> {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] Malformed QR code ${msg.requestId}")
|
||||||
msg.deferred.completeExceptionally(IllegalArgumentException("Malformed QrCode data"))
|
msg.deferred.completeExceptionally(IllegalArgumentException("Malformed QrCode data"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -629,93 +698,85 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
// key2 (aka otherUserMasterCrossSigningPublicKey) is what the one displaying the QR code (other user) think my MSK is.
|
// key2 (aka otherUserMasterCrossSigningPublicKey) is what the one displaying the QR code (other user) think my MSK is.
|
||||||
// Let's check that it's correct
|
// Let's check that it's correct
|
||||||
// If not -> Cancel
|
// If not -> Cancel
|
||||||
if (otherQrCodeData.otherUserMasterCrossSigningPublicKey != myMasterKey) {
|
val whatOtherThinksMyMskIs = otherQrCodeData.otherUserMasterCrossSigningPublicKey
|
||||||
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.otherUserMasterCrossSigningPublicKey}")
|
if (whatOtherThinksMyMskIs != myMasterKey) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] ## Verification QR: Invalid other master key ${otherQrCodeData.otherUserMasterCrossSigningPublicKey}")
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
msg.deferred.complete(null)
|
msg.deferred.complete(null)
|
||||||
return
|
return
|
||||||
} else Unit
|
}
|
||||||
|
|
||||||
|
val whatIThinkOtherMskIs = crossSigningService.get().getUserCrossSigningKeys(matchingRequest.otherUserId)
|
||||||
|
?.masterKey()
|
||||||
|
?.unpaddedBase64PublicKey
|
||||||
|
if (whatIThinkOtherMskIs != otherQrCodeData.userMasterCrossSigningPublicKey) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] ## Verification QR: Invalid other master key ${otherQrCodeData.otherUserMasterCrossSigningPublicKey}")
|
||||||
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
|
msg.deferred.complete(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
|
is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
|
||||||
|
if (matchingRequest.otherUserId != myUserId) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] Self mode qr with wrong user ${matchingRequest.otherUserId}")
|
||||||
|
cancelRequest(matchingRequest, CancelCode.MismatchedUser)
|
||||||
|
msg.deferred.complete(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
// key1 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
|
// key1 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
|
||||||
// Let's check that I see the same MSK
|
// Let's check that I see the same MSK
|
||||||
// If not -> Cancel
|
// If not -> Cancel
|
||||||
if (otherQrCodeData.userMasterCrossSigningPublicKey != myMasterKey) {
|
val whatOtherThinksOurMskIs = otherQrCodeData.userMasterCrossSigningPublicKey
|
||||||
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
if (whatOtherThinksOurMskIs != myMasterKey) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] ## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
||||||
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
|
msg.deferred.complete(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val whatOtherThinkMyDeviceKeyIs = otherQrCodeData.otherDeviceKey
|
||||||
|
val myDeviceKey = cryptoStore.getUserDevice(myUserId, cryptoStore.getDeviceId())?.fingerprint()
|
||||||
|
if (whatOtherThinkMyDeviceKeyIs != myDeviceKey) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] ## Verification QR: Invalid other device key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
msg.deferred.complete(null)
|
msg.deferred.complete(null)
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
// I can trust the MSK then (i see the same one, and other session tell me it's trusted by him)
|
|
||||||
canTrustOtherUserMasterKey = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> {
|
is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> {
|
||||||
|
if (matchingRequest.otherUserId != myUserId) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] Self mode qr with wrong user ${matchingRequest.otherUserId}")
|
||||||
|
cancelRequest(matchingRequest, CancelCode.MismatchedUser)
|
||||||
|
msg.deferred.complete(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
// key2 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
|
// key2 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
|
||||||
// Let's check that it's the good one
|
// Let's check that it's the good one
|
||||||
// If not -> Cancel
|
// If not -> Cancel
|
||||||
if (otherQrCodeData.userMasterCrossSigningPublicKey != myMasterKey) {
|
val otherDeclaredDeviceKey = otherQrCodeData.deviceKey
|
||||||
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
val whatIThinkItIs = cryptoStore.getUserDevice(myUserId, otherDeviceId)?.fingerprint()
|
||||||
|
|
||||||
|
if (otherDeclaredDeviceKey != whatIThinkItIs) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] ## Verification QR: Invalid other device key $otherDeviceId")
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
msg.deferred.complete(null)
|
msg.deferred.complete(null)
|
||||||
return
|
|
||||||
} else {
|
|
||||||
// Nothing special here, we will send a reciprocate start event, and then the other session will trust it's view of the MSK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val toVerifyDeviceIds = mutableListOf<String>()
|
val ownMasterKeyTrustedAsSeenByOther = otherQrCodeData.userMasterCrossSigningPublicKey
|
||||||
|
if (ownMasterKeyTrustedAsSeenByOther != myMasterKey) {
|
||||||
// Let's now check the other user/device key material
|
Timber.tag(loggerTag.value)
|
||||||
when (otherQrCodeData) {
|
.d("[${myUserId.take(8)}] ## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
||||||
is QrCodeData.VerifyingAnotherUser -> {
|
|
||||||
// key1(aka userMasterCrossSigningPublicKey) is the MSK of the one displaying the QR code (i.e other user)
|
|
||||||
// Let's check that it matches what I think it should be
|
|
||||||
if (otherQrCodeData.userMasterCrossSigningPublicKey
|
|
||||||
!= crossSigningService.get().getUserCrossSigningKeys(msg.otherUserId)?.masterKey()?.unpaddedBase64PublicKey) {
|
|
||||||
Timber.d("## Verification QR: Invalid user master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
msg.deferred.complete(null)
|
msg.deferred.complete(null)
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
// It does so i should mark it as trusted
|
|
||||||
canTrustOtherUserMasterKey = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
|
|
||||||
// key2 (aka otherDeviceKey) is my current device key in POV of the one displaying the QR code (i.e other device)
|
|
||||||
// Let's check that it's correct
|
|
||||||
if (otherQrCodeData.otherDeviceKey
|
|
||||||
!= cryptoStore.getUserDevice(myUserId, cryptoStore.getDeviceId())?.fingerprint()) {
|
|
||||||
Timber.d("## Verification QR: Invalid other device key ${otherQrCodeData.otherDeviceKey}")
|
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
|
||||||
msg.deferred.complete(null)
|
|
||||||
return
|
|
||||||
} else Unit // Nothing special here, we will send a reciprocate start event, and then the other session will trust my device
|
|
||||||
// and thus allow me to request SSSS secret
|
|
||||||
}
|
|
||||||
is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> {
|
|
||||||
// key1 (aka otherDeviceKey) is the device key of the one displaying the QR code (i.e other device)
|
|
||||||
// Let's check that it matches what I have locally
|
|
||||||
if (otherQrCodeData.deviceKey
|
|
||||||
!= cryptoStore.getUserDevice(msg.otherUserId, otherDeviceId ?: "")?.fingerprint()) {
|
|
||||||
Timber.d("## Verification QR: Invalid device key ${otherQrCodeData.deviceKey}")
|
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
|
||||||
msg.deferred.complete(null)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
// Yes it does -> i should trust it and sign then upload the signature
|
|
||||||
toVerifyDeviceIds.add(otherDeviceId ?: "")
|
|
||||||
Unit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!canTrustOtherUserMasterKey && toVerifyDeviceIds.isEmpty()) {
|
|
||||||
// Nothing to verify
|
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All checks are correct
|
// All checks are correct
|
||||||
@ -746,6 +807,8 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
try {
|
try {
|
||||||
sendToOther(matchingRequest, EventType.KEY_VERIFICATION_START, message)
|
sendToOther(matchingRequest, EventType.KEY_VERIFICATION_START, message)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}] Failed to send reciprocate message")
|
||||||
msg.deferred.completeExceptionally(failure)
|
msg.deferred.completeExceptionally(failure)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -754,21 +817,45 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||||
|
|
||||||
val tx = KotlinQRVerification(
|
val tx = KotlinQRVerification(
|
||||||
qrCodeText = msg.scannedData,
|
channel = this.channel,
|
||||||
state = VerificationTxState.WaitingOtherReciprocateConfirm,
|
state = QRCodeVerificationState.Reciprocated,
|
||||||
|
qrCodeData = msg.scannedData.toQrCodeData(),
|
||||||
method = VerificationMethod.QR_CODE_SCAN,
|
method = VerificationMethod.QR_CODE_SCAN,
|
||||||
transactionId = msg.requestId,
|
transactionId = msg.requestId,
|
||||||
otherUserId = msg.otherUserId,
|
otherUserId = msg.otherUserId,
|
||||||
otherDeviceId = matchingRequest.otherDeviceId(),
|
otherDeviceId = matchingRequest.otherDeviceId(),
|
||||||
isIncoming = false
|
isIncoming = false,
|
||||||
|
isToDevice = matchingRequest.roomId == null
|
||||||
)
|
)
|
||||||
|
|
||||||
addTransaction(tx)
|
addTransaction(tx)
|
||||||
|
msg.deferred.complete(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun handleActionQRScanConfirmed(matchingRequest: KotlinVerificationRequest) {
|
||||||
|
val transaction = getExistingTransaction<KotlinQRVerification>(matchingRequest.otherUserId, matchingRequest.requestId)
|
||||||
|
if (transaction == null) {
|
||||||
|
// return
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}]: No matching transaction for key tId:${matchingRequest.requestId}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transaction.state() == QRCodeVerificationState.WaitingForScanConfirmation) {
|
||||||
|
completeValidQRTransaction(transaction, matchingRequest)
|
||||||
|
} else {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}]: Unexpected confirm in state tId:${matchingRequest.requestId}")
|
||||||
|
// TODO throw?
|
||||||
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleReceiveKey(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnKeyReceived) {
|
private suspend fun handleReceiveKey(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnKeyReceived) {
|
||||||
val requestId = msg.validKey.transactionId
|
val requestId = msg.validKey.transactionId
|
||||||
|
|
||||||
val existing = getExistingTransaction(msg.fromUser, requestId)
|
val existing: KotlinSasTransaction = getExistingTransaction(msg.fromUser, requestId)
|
||||||
?: return Unit.also {
|
?: return Unit.also {
|
||||||
Timber.tag(loggerTag.value)
|
Timber.tag(loggerTag.value)
|
||||||
.v("[${myUserId.take(8)}]: No matching transaction for key tId:$requestId")
|
.v("[${myUserId.take(8)}]: No matching transaction for key tId:$requestId")
|
||||||
@ -776,9 +863,9 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
|
|
||||||
// Existing should be in SAS key sent
|
// Existing should be in SAS key sent
|
||||||
val isCorrectState = if (existing.isIncoming) {
|
val isCorrectState = if (existing.isIncoming) {
|
||||||
existing.state == VerificationTxState.SasAccepted
|
existing.state == SasTransactionState.SasAccepted
|
||||||
} else {
|
} else {
|
||||||
existing.state == VerificationTxState.SasKeySent
|
existing.state == SasTransactionState.SasKeySent
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCorrectState) {
|
if (!isCorrectState) {
|
||||||
@ -792,7 +879,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
if (existing.isIncoming) {
|
if (existing.isIncoming) {
|
||||||
// ok i can now send my key and compute the sas code
|
// ok i can now send my key and compute the sas code
|
||||||
val pubKey = existing.getSAS().publicKey
|
val pubKey = existing.getSAS().publicKey
|
||||||
val keyMessage = SasV1Transaction.sasKeyMessage(matchingRequest.roomId != null, requestId, pubKey)
|
val keyMessage = KotlinSasTransaction.sasKeyMessage(matchingRequest.roomId != null, requestId, pubKey)
|
||||||
try {
|
try {
|
||||||
sendToOther(
|
sendToOther(
|
||||||
matchingRequest,
|
matchingRequest,
|
||||||
@ -804,7 +891,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
.v("[${myUserId.take(8)}]:i calculate SAS my key $pubKey their Key: $otherKey")
|
.v("[${myUserId.take(8)}]:i calculate SAS my key $pubKey their Key: $otherKey")
|
||||||
}
|
}
|
||||||
existing.calculateSASBytes(otherKey)
|
existing.calculateSASBytes(otherKey)
|
||||||
existing.state = VerificationTxState.SasShortCodeReady
|
existing.state = SasTransactionState.SasShortCodeReady
|
||||||
if (BuildConfig.LOG_PRIVATE_DATA) {
|
if (BuildConfig.LOG_PRIVATE_DATA) {
|
||||||
Timber.tag(loggerTag.value)
|
Timber.tag(loggerTag.value)
|
||||||
.v("[${myUserId.take(8)}]:i CODE ${existing.getDecimalCodeRepresentation()}")
|
.v("[${myUserId.take(8)}]:i CODE ${existing.getDecimalCodeRepresentation()}")
|
||||||
@ -813,7 +900,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
existing.state = VerificationTxState.Cancelled(CancelCode.UserError, true)
|
existing.state = SasTransactionState.Cancelled(CancelCode.UserError, true)
|
||||||
matchingRequest.state = EVerificationState.Cancelled
|
matchingRequest.state = EVerificationState.Cancelled
|
||||||
matchingRequest.cancelCode = CancelCode.UserError
|
matchingRequest.cancelCode = CancelCode.UserError
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
@ -843,7 +930,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
.v("[${myUserId.take(8)}]:o calculate SAS my key ${existing.getSAS().publicKey} their Key: $otherKey")
|
.v("[${myUserId.take(8)}]:o calculate SAS my key ${existing.getSAS().publicKey} their Key: $otherKey")
|
||||||
}
|
}
|
||||||
existing.calculateSASBytes(otherKey)
|
existing.calculateSASBytes(otherKey)
|
||||||
existing.state = VerificationTxState.SasShortCodeReady
|
existing.state = SasTransactionState.SasShortCodeReady
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
if (BuildConfig.LOG_PRIVATE_DATA) {
|
if (BuildConfig.LOG_PRIVATE_DATA) {
|
||||||
Timber.tag(loggerTag.value)
|
Timber.tag(loggerTag.value)
|
||||||
@ -864,21 +951,21 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
private suspend fun handleMacReceived(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnMacReceived) {
|
private suspend fun handleMacReceived(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnMacReceived) {
|
||||||
val requestId = msg.validMac.transactionId
|
val requestId = msg.validMac.transactionId
|
||||||
|
|
||||||
val existing = getExistingTransaction(msg.fromUser, requestId)
|
val existing: KotlinSasTransaction = getExistingTransaction(msg.fromUser, requestId)
|
||||||
?: return Unit.also {
|
?: return Unit.also {
|
||||||
Timber.tag(loggerTag.value)
|
Timber.tag(loggerTag.value)
|
||||||
.v("[${myUserId.take(8)}] on Mac for unknown transaction with id:$requestId")
|
.v("[${myUserId.take(8)}] on Mac for unknown transaction with id:$requestId")
|
||||||
}
|
}
|
||||||
|
|
||||||
when (existing.state) {
|
when (existing.state) {
|
||||||
is VerificationTxState.SasMacSent -> {
|
is SasTransactionState.SasMacSent -> {
|
||||||
existing.theirMac = msg.validMac
|
existing.theirMac = msg.validMac
|
||||||
finalizeSasTransaction(existing, msg.validMac, matchingRequest, existing.transactionId)
|
finalizeSasTransaction(existing, msg.validMac, matchingRequest, existing.transactionId)
|
||||||
}
|
}
|
||||||
is VerificationTxState.SasShortCodeReady -> {
|
is SasTransactionState.SasShortCodeReady -> {
|
||||||
// I can start verify, store it
|
// I can start verify, store it
|
||||||
existing.theirMac = msg.validMac
|
existing.theirMac = msg.validMac
|
||||||
existing.state = VerificationTxState.SasMacReceived(false)
|
existing.state = SasTransactionState.SasMacReceived(false)
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@ -901,14 +988,14 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
msg.deferred.completeExceptionally(IllegalStateException("Request was cancelled"))
|
msg.deferred.completeExceptionally(IllegalStateException("Request was cancelled"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val existing = getExistingTransaction(transactionId)
|
val existing: KotlinSasTransaction = getExistingTransaction(transactionId)
|
||||||
?: return Unit.also {
|
?: return Unit.also {
|
||||||
msg.deferred.completeExceptionally(IllegalStateException("Unknown Transaction"))
|
msg.deferred.completeExceptionally(IllegalStateException("Unknown Transaction"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val isCorrectState = when (val state = existing.state) {
|
val isCorrectState = when (val state = existing.state) {
|
||||||
is VerificationTxState.SasShortCodeReady -> true
|
is SasTransactionState.SasShortCodeReady -> true
|
||||||
is VerificationTxState.SasMacReceived -> !state.codeConfirmed
|
is SasTransactionState.SasMacReceived -> !state.codeConfirmed
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
if (!isCorrectState) {
|
if (!isCorrectState) {
|
||||||
@ -927,25 +1014,122 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
private suspend fun handleDoneReceived(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnDoneReceived) {
|
private suspend fun handleDoneReceived(matchingRequest: KotlinVerificationRequest, msg: VerificationIntent.OnDoneReceived) {
|
||||||
val requestId = msg.transactionId
|
val requestId = msg.transactionId
|
||||||
|
|
||||||
val existing = getExistingTransaction(msg.fromUser, requestId)
|
val existing: VerificationTransaction = getExistingTransaction(msg.fromUser, requestId)
|
||||||
?: return Unit.also {
|
?: return Unit.also {
|
||||||
Timber.v("on accept received in room ${msg.viaRoom} for verification id:${requestId} in room ${matchingRequest.roomId}")
|
Timber.v("on accept received in room ${msg.viaRoom} for verification id:${requestId} in room ${matchingRequest.roomId}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when {
|
||||||
|
existing is KotlinSasTransaction -> {
|
||||||
val state = existing.state
|
val state = existing.state
|
||||||
val isCorrectState = state is VerificationTxState.Done && !state.otherDone
|
val isCorrectState = state is SasTransactionState.Done && !state.otherDone
|
||||||
|
|
||||||
if (isCorrectState) {
|
if (isCorrectState) {
|
||||||
|
existing.state = SasTransactionState.Done(true)
|
||||||
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
|
// we can forget about it
|
||||||
|
txMap[matchingRequest.otherUserId()]?.remove(matchingRequest.requestId)
|
||||||
// XXX whatabout waiting for done?
|
// XXX whatabout waiting for done?
|
||||||
matchingRequest.state = EVerificationState.Done
|
matchingRequest.state = EVerificationState.Done
|
||||||
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||||
// updatePendingRequest(
|
|
||||||
// matchingRequest.copy(
|
|
||||||
// isSuccessful = true
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
} else {
|
} else {
|
||||||
// TODO cancel?
|
// TODO cancel?
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}]: Unexpected done in state $state")
|
||||||
|
|
||||||
|
cancelRequest(matchingRequest, CancelCode.UnexpectedMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
existing is KotlinQRVerification -> {
|
||||||
|
val state = existing.state()
|
||||||
|
when (state) {
|
||||||
|
QRCodeVerificationState.Reciprocated -> {
|
||||||
|
completeValidQRTransaction(existing, matchingRequest)
|
||||||
|
}
|
||||||
|
QRCodeVerificationState.WaitingForOtherDone -> {
|
||||||
|
matchingRequest.state = EVerificationState.Done
|
||||||
|
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Timber.tag(loggerTag.value)
|
||||||
|
.d("[${myUserId.take(8)}]: Unexpected done in state $state")
|
||||||
|
cancelRequest(matchingRequest, CancelCode.UnexpectedMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// unexpected message?
|
||||||
|
cancelRequest(matchingRequest, CancelCode.UnexpectedMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun completeValidQRTransaction(existing: KotlinQRVerification, matchingRequest: KotlinVerificationRequest) {
|
||||||
|
var shouldRequestSecret = false
|
||||||
|
// Ok so the other side is fine let's trust what we need to trust
|
||||||
|
when (existing.qrCodeData) {
|
||||||
|
is QrCodeData.VerifyingAnotherUser -> {
|
||||||
|
// let's trust him
|
||||||
|
// it's his code scanned so user is him and other me
|
||||||
|
try {
|
||||||
|
crossSigningService.get().trustUser(matchingRequest.otherUserId)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
// fail silently?
|
||||||
|
// at least it will be marked as trusted locally?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> {
|
||||||
|
// the other device is the one that doesn't trust yet our MSK
|
||||||
|
// As all is good I can upload a signature for my new device
|
||||||
|
|
||||||
|
// Also notify the secret share manager for the soon to come secret share requests
|
||||||
|
secretShareManager.onVerificationCompleteForDevice(matchingRequest.otherDeviceId()!!)
|
||||||
|
try {
|
||||||
|
crossSigningService.get().trustDevice(matchingRequest.otherDeviceId()!!)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
// network problem??
|
||||||
|
Timber.w("## Verification: Failed to sign new device ${matchingRequest.otherDeviceId()}, ${failure.localizedMessage}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
|
||||||
|
// I can trust my MSK
|
||||||
|
crossSigningService.get().markMyMasterKeyAsTrusted()
|
||||||
|
shouldRequestSecret = true
|
||||||
|
}
|
||||||
|
null -> {
|
||||||
|
// This shouldn't happen? cancel?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToOther(
|
||||||
|
matchingRequest,
|
||||||
|
EventType.KEY_VERIFICATION_DONE,
|
||||||
|
if (matchingRequest.roomId != null) {
|
||||||
|
MessageVerificationDoneContent(
|
||||||
|
relatesTo = RelationDefaultContent(
|
||||||
|
RelationType.REFERENCE,
|
||||||
|
matchingRequest.requestId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KeyVerificationDone(matchingRequest.requestId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
existing.state = QRCodeVerificationState.Done
|
||||||
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
|
// we can forget about it
|
||||||
|
txMap[matchingRequest.otherUserId()]?.remove(matchingRequest.requestId)
|
||||||
|
matchingRequest.state = EVerificationState.WaitingForDone
|
||||||
|
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||||
|
|
||||||
|
if (shouldRequestSecret) {
|
||||||
|
matchingRequest.otherDeviceId()?.let { otherDeviceId ->
|
||||||
|
secretShareManager.requestSecretTo(otherDeviceId, MASTER_KEY_SSSS_NAME)
|
||||||
|
secretShareManager.requestSecretTo(otherDeviceId, SELF_SIGNING_KEY_SSSS_NAME)
|
||||||
|
secretShareManager.requestSecretTo(otherDeviceId, USER_SIGNING_KEY_SSSS_NAME)
|
||||||
|
secretShareManager.requestSecretTo(otherDeviceId, KEYBACKUP_SECRET_SSSS_NAME)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,21 +1140,21 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
msg.deferred.completeExceptionally(IllegalStateException("Unknown Request"))
|
msg.deferred.completeExceptionally(IllegalStateException("Unknown Request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchingRequest.state != EVerificationState.WeStarted
|
if (matchingRequest.state != EVerificationState.WeStarted &&
|
||||||
&& matchingRequest.state != EVerificationState.Started) {
|
matchingRequest.state != EVerificationState.Started) {
|
||||||
return Unit.also {
|
return Unit.also {
|
||||||
msg.deferred.completeExceptionally(IllegalStateException("Can't accept code in state: ${matchingRequest.state}"))
|
msg.deferred.completeExceptionally(IllegalStateException("Can't accept code in state: ${matchingRequest.state}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val existing = getExistingTransaction(transactionId)
|
val existing: KotlinSasTransaction = getExistingTransaction(transactionId)
|
||||||
?: return Unit.also {
|
?: return Unit.also {
|
||||||
msg.deferred.completeExceptionally(IllegalStateException("Unknown Transaction"))
|
msg.deferred.completeExceptionally(IllegalStateException("Unknown Transaction"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val isCorrectState = when (val state = existing.state) {
|
val isCorrectState = when (val state = existing.state) {
|
||||||
is VerificationTxState.SasShortCodeReady -> true
|
is SasTransactionState.SasShortCodeReady -> true
|
||||||
is VerificationTxState.SasMacReceived -> !state.codeConfirmed
|
is SasTransactionState.SasMacReceived -> !state.codeConfirmed
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
if (!isCorrectState) {
|
if (!isCorrectState) {
|
||||||
@ -981,7 +1165,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
|
|
||||||
val macInfo = existing.computeMyMac()
|
val macInfo = existing.computeMyMac()
|
||||||
|
|
||||||
val macMsg = SasV1Transaction.sasMacMessage(matchingRequest.roomId != null, transactionId, macInfo)
|
val macMsg = KotlinSasTransaction.sasMacMessage(matchingRequest.roomId != null, transactionId, macInfo)
|
||||||
try {
|
try {
|
||||||
sendToOther(matchingRequest, EventType.KEY_VERIFICATION_MAC, macMsg)
|
sendToOther(matchingRequest, EventType.KEY_VERIFICATION_MAC, macMsg)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
@ -995,7 +1179,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
if (theirMac != null) {
|
if (theirMac != null) {
|
||||||
finalizeSasTransaction(existing, theirMac, matchingRequest, transactionId)
|
finalizeSasTransaction(existing, theirMac, matchingRequest, transactionId)
|
||||||
} else {
|
} else {
|
||||||
existing.state = VerificationTxState.SasMacSent
|
existing.state = SasTransactionState.SasMacSent
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1003,7 +1187,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun finalizeSasTransaction(
|
private suspend fun finalizeSasTransaction(
|
||||||
existing: SasV1Transaction,
|
existing: KotlinSasTransaction,
|
||||||
theirMac: ValidVerificationInfoMac,
|
theirMac: ValidVerificationInfoMac,
|
||||||
matchingRequest: KotlinVerificationRequest,
|
matchingRequest: KotlinVerificationRequest,
|
||||||
transactionId: String
|
transactionId: String
|
||||||
@ -1017,7 +1201,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
Timber.tag(loggerTag.value)
|
Timber.tag(loggerTag.value)
|
||||||
.v("[${myUserId.take(8)}] verify macs result $result id:$transactionId")
|
.v("[${myUserId.take(8)}] verify macs result $result id:$transactionId")
|
||||||
when (result) {
|
when (result) {
|
||||||
is SasV1Transaction.MacVerificationResult.Success -> {
|
is KotlinSasTransaction.MacVerificationResult.Success -> {
|
||||||
// mark the devices as locally trusted
|
// mark the devices as locally trusted
|
||||||
result.verifiedDeviceId.forEach { deviceId ->
|
result.verifiedDeviceId.forEach { deviceId ->
|
||||||
val actualTrustLevel = cryptoStore.getUserDevice(matchingRequest.otherUserId, deviceId)?.trustLevel
|
val actualTrustLevel = cryptoStore.getUserDevice(matchingRequest.otherUserId, deviceId)?.trustLevel
|
||||||
@ -1068,17 +1252,17 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
existing.state = VerificationTxState.Done(false)
|
existing.state = SasTransactionState.Done(false)
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(existing))
|
||||||
pastTransactions.getOrPut(transactionId) { mutableMapOf() }[transactionId] = existing
|
pastTransactions.getOrPut(transactionId) { mutableMapOf() }[transactionId] = existing
|
||||||
txMap[matchingRequest.otherUserId]?.remove(transactionId)
|
txMap[matchingRequest.otherUserId]?.remove(transactionId)
|
||||||
matchingRequest.state = EVerificationState.WaitingForDone
|
matchingRequest.state = EVerificationState.WaitingForDone
|
||||||
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
eventFlow.emit(VerificationEvent.RequestUpdated(matchingRequest.toPendingVerificationRequest()))
|
||||||
}
|
}
|
||||||
SasV1Transaction.MacVerificationResult.MismatchKeys,
|
KotlinSasTransaction.MacVerificationResult.MismatchKeys,
|
||||||
SasV1Transaction.MacVerificationResult.MismatchMacCrossSigning,
|
KotlinSasTransaction.MacVerificationResult.MismatchMacCrossSigning,
|
||||||
is SasV1Transaction.MacVerificationResult.MismatchMacDevice,
|
is KotlinSasTransaction.MacVerificationResult.MismatchMacDevice,
|
||||||
SasV1Transaction.MacVerificationResult.NoDevicesVerified -> {
|
KotlinSasTransaction.MacVerificationResult.NoDevicesVerified -> {
|
||||||
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
cancelRequest(matchingRequest, CancelCode.MismatchedKeys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1126,7 +1310,7 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
commonMethods
|
commonMethods
|
||||||
)
|
)
|
||||||
|
|
||||||
val message = SasV1Transaction.sasReady(
|
val message = KotlinSasTransaction.sasReady(
|
||||||
inRoom = existing.roomId != null,
|
inRoom = existing.roomId != null,
|
||||||
requestId = msg.transactionId,
|
requestId = msg.transactionId,
|
||||||
methods = commonMethods,
|
methods = commonMethods,
|
||||||
@ -1533,11 +1717,17 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
eventFlow.emit(VerificationEvent.RequestUpdated(request.toPendingVerificationRequest()))
|
eventFlow.emit(VerificationEvent.RequestUpdated(request.toPendingVerificationRequest()))
|
||||||
|
|
||||||
// should also update SAS/QR transaction
|
// should also update SAS/QR transaction
|
||||||
getExistingTransaction(request.otherUserId, request.requestId)?.let {
|
getExistingTransaction<KotlinSasTransaction>(request.otherUserId, request.requestId)?.let {
|
||||||
it.state = VerificationTxState.Cancelled(code, true)
|
it.state = SasTransactionState.Cancelled(code, true)
|
||||||
txMap[request.otherUserId]?.remove(request.requestId)
|
txMap[request.otherUserId]?.remove(request.requestId)
|
||||||
eventFlow.emit(VerificationEvent.TransactionUpdated(it))
|
eventFlow.emit(VerificationEvent.TransactionUpdated(it))
|
||||||
}
|
}
|
||||||
|
getExistingTransaction<KotlinQRVerification>(request.otherUserId, request.requestId)?.let {
|
||||||
|
it.state = QRCodeVerificationState.Cancelled
|
||||||
|
txMap[request.otherUserId]?.remove(request.requestId)
|
||||||
|
eventFlow.emit(VerificationEvent.TransactionUpdated(it))
|
||||||
|
}
|
||||||
|
|
||||||
cancelRequest(request.requestId, request.roomId, request.otherUserId, request.otherDeviceId(), code)
|
cancelRequest(request.requestId, request.roomId, request.otherUserId, request.otherDeviceId(), code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1592,17 +1782,17 @@ internal class VerificationActor @AssistedInject constructor(
|
|||||||
throw java.lang.IllegalArgumentException("Unsupported hash method $hashMethod")
|
throw java.lang.IllegalArgumentException("Unsupported hash method $hashMethod")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun addTransaction(tx: SasV1Transaction) {
|
private suspend fun addTransaction(tx: VerificationTransaction) {
|
||||||
val txInnerMap = txMap.getOrPut(tx.otherUserId) { mutableMapOf() }
|
val txInnerMap = txMap.getOrPut(tx.otherUserId) { mutableMapOf() }
|
||||||
txInnerMap[tx.transactionId] = tx
|
txInnerMap[tx.transactionId] = tx
|
||||||
eventFlow.emit(VerificationEvent.TransactionAdded(tx))
|
eventFlow.emit(VerificationEvent.TransactionAdded(tx))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getExistingTransaction(otherUserId: String, transactionId: String): SasV1Transaction? {
|
private inline fun <reified T : VerificationTransaction> getExistingTransaction(otherUserId: String, transactionId: String): T? {
|
||||||
return txMap[otherUserId]?.get(transactionId)
|
return txMap[otherUserId]?.get(transactionId) as? T
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T: VerificationTransaction> getExistingTransaction(transactionId: String, type: T): T? {
|
private inline fun <reified T : VerificationTransaction> getExistingTransaction(transactionId: String): T? {
|
||||||
txMap.forEach {
|
txMap.forEach {
|
||||||
val match = it.value.values
|
val match = it.value.values
|
||||||
.firstOrNull { it.transactionId == transactionId }
|
.firstOrNull { it.transactionId == transactionId }
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package org.matrix.android.sdk.internal.crypto.verification
|
package org.matrix.android.sdk.internal.crypto.verification
|
||||||
|
|
||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.IVerificationRequest
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
|
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoRequest
|
||||||
@ -106,6 +105,12 @@ internal sealed class VerificationIntent {
|
|||||||
val deferred: CompletableDeferred<VerificationTransaction?>,
|
val deferred: CompletableDeferred<VerificationTransaction?>,
|
||||||
) : VerificationIntent()
|
) : VerificationIntent()
|
||||||
|
|
||||||
|
data class ActionConfirmCodeWasScanned(
|
||||||
|
val otherUserId: String,
|
||||||
|
val requestId: String,
|
||||||
|
val deferred: CompletableDeferred<Unit>,
|
||||||
|
) : VerificationIntent()
|
||||||
|
|
||||||
data class OnStartReceived(
|
data class OnStartReceived(
|
||||||
val viaRoom: String?,
|
val viaRoom: String?,
|
||||||
val fromUser: String,
|
val fromUser: String,
|
||||||
|
@ -23,8 +23,6 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
|||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationReadyContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationReadyContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationStartContent
|
|
||||||
import org.matrix.android.sdk.internal.di.DeviceId
|
import org.matrix.android.sdk.internal.di.DeviceId
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
import org.matrix.android.sdk.internal.util.time.Clock
|
import org.matrix.android.sdk.internal.util.time.Clock
|
||||||
@ -56,7 +54,7 @@ internal class VerificationMessageProcessor @Inject constructor(
|
|||||||
return allowedTypes.contains(eventType)
|
return allowedTypes.contains(eventType)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun process(roomId:String, event: Event) {
|
suspend fun process(roomId: String, event: Event) {
|
||||||
Timber.v("## SAS Verification live observer: received msgId: ${event.eventId} msgtype: ${event.getClearType()} from ${event.senderId}")
|
Timber.v("## SAS Verification live observer: received msgId: ${event.eventId} msgtype: ${event.getClearType()} from ${event.senderId}")
|
||||||
|
|
||||||
// If the request is in the future by more than 5 minutes or more than 10 minutes in the past,
|
// If the request is in the future by more than 5 minutes or more than 10 minutes in the past,
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.session.crypto.verification
|
package org.matrix.android.sdk.api.session.crypto.verification
|
||||||
|
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.KotlinVerificationRequest
|
|
||||||
|
|
||||||
enum class EVerificationState {
|
enum class EVerificationState {
|
||||||
// outgoing started request
|
// outgoing started request
|
||||||
WaitingForReady,
|
WaitingForReady,
|
||||||
|
|
||||||
// for incoming
|
// for incoming
|
||||||
Requested,
|
Requested,
|
||||||
|
|
||||||
// both incoming/outgoing
|
// both incoming/outgoing
|
||||||
Ready,
|
Ready,
|
||||||
Started,
|
Started,
|
||||||
@ -34,15 +34,16 @@ enum class EVerificationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove that
|
// TODO remove that
|
||||||
interface IVerificationRequest{
|
interface IVerificationRequest {
|
||||||
|
|
||||||
fun requestId(): String
|
fun requestId(): String
|
||||||
|
|
||||||
fun incoming(): Boolean
|
fun incoming(): Boolean
|
||||||
fun otherUserId(): String
|
fun otherUserId(): String
|
||||||
fun roomId(): String?
|
fun roomId(): String?
|
||||||
|
|
||||||
// target devices in case of to_device self verification
|
// target devices in case of to_device self verification
|
||||||
fun targetDevices() : List<String>?
|
fun targetDevices(): List<String>?
|
||||||
|
|
||||||
fun state(): EVerificationState
|
fun state(): EVerificationState
|
||||||
fun ageLocalTs(): Long
|
fun ageLocalTs(): Long
|
||||||
@ -53,10 +54,9 @@ interface IVerificationRequest{
|
|||||||
|
|
||||||
fun otherDeviceId(): String?
|
fun otherDeviceId(): String?
|
||||||
|
|
||||||
fun qrCodeText() : String?
|
fun qrCodeText(): String?
|
||||||
|
|
||||||
fun isFinished() : Boolean = state() == EVerificationState.Cancelled || state() == EVerificationState.Done
|
fun isFinished(): Boolean = state() == EVerificationState.Cancelled || state() == EVerificationState.Done
|
||||||
|
|
||||||
fun cancelCode(): CancelCode?
|
fun cancelCode(): CancelCode?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.matrix.android.sdk.api.session.crypto.verification
|
package org.matrix.android.sdk.api.session.crypto.verification
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SCAN
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores current pending verification requests.
|
* Stores current pending verification requests.
|
||||||
*/
|
*/
|
||||||
@ -34,7 +27,7 @@ data class PendingVerificationRequest(
|
|||||||
val otherDeviceId: String?,
|
val otherDeviceId: String?,
|
||||||
// in case of verification via room, it will be not null
|
// in case of verification via room, it will be not null
|
||||||
val roomId: String?,
|
val roomId: String?,
|
||||||
val transactionId: String,//? = null,
|
val transactionId: String, // ? = null,
|
||||||
// val requestInfo: ValidVerificationInfoRequest? = null,
|
// val requestInfo: ValidVerificationInfoRequest? = null,
|
||||||
// val readyInfo: ValidVerificationInfoReady? = null,
|
// val readyInfo: ValidVerificationInfoReady? = null,
|
||||||
val cancelConclusion: CancelCode? = null,
|
val cancelConclusion: CancelCode? = null,
|
||||||
@ -52,5 +45,4 @@ data class PendingVerificationRequest(
|
|||||||
// val isReady: Boolean = readyInfo != null
|
// val isReady: Boolean = readyInfo != null
|
||||||
//
|
//
|
||||||
// val isFinished: Boolean = isSuccessful || cancelConclusion != null
|
// val isFinished: Boolean = isSuccessful || cancelConclusion != null
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,22 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.session.crypto.verification
|
package org.matrix.android.sdk.api.session.crypto.verification
|
||||||
|
|
||||||
|
enum class QRCodeVerificationState {
|
||||||
|
// ie. we started
|
||||||
|
Reciprocated,
|
||||||
|
|
||||||
|
// When started/scanned by other side and waiting for confirmation
|
||||||
|
// that was really scanned
|
||||||
|
WaitingForScanConfirmation,
|
||||||
|
WaitingForOtherDone,
|
||||||
|
Done,
|
||||||
|
Cancelled
|
||||||
|
}
|
||||||
|
|
||||||
interface QrCodeVerificationTransaction : VerificationTransaction {
|
interface QrCodeVerificationTransaction : VerificationTransaction {
|
||||||
|
|
||||||
|
fun state(): QRCodeVerificationState
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To use to display a qr code, for the other user to scan it.
|
* To use to display a qr code, for the other user to scan it.
|
||||||
*/
|
*/
|
||||||
@ -26,7 +40,7 @@ interface QrCodeVerificationTransaction : VerificationTransaction {
|
|||||||
/**
|
/**
|
||||||
* Call when you have scan the other user QR code.
|
* Call when you have scan the other user QR code.
|
||||||
*/
|
*/
|
||||||
suspend fun userHasScannedOtherQrCode(otherQrCodeText: String)
|
// suspend fun userHasScannedOtherQrCode(otherQrCodeText: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call when you confirm that other user has scanned your QR code.
|
* Call when you confirm that other user has scanned your QR code.
|
||||||
@ -37,4 +51,6 @@ interface QrCodeVerificationTransaction : VerificationTransaction {
|
|||||||
* Call when you do not confirm that other user has scanned your QR code.
|
* Call when you do not confirm that other user has scanned your QR code.
|
||||||
*/
|
*/
|
||||||
suspend fun otherUserDidNotScannedMyQrCode()
|
suspend fun otherUserDidNotScannedMyQrCode()
|
||||||
|
|
||||||
|
override fun isSuccessful() = state() == QRCodeVerificationState.Done
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,10 @@ interface SasVerificationTransaction : VerificationTransaction {
|
|||||||
val KNOWN_SHORT_CODES = listOf(SasMode.EMOJI, SasMode.DECIMAL)
|
val KNOWN_SHORT_CODES = listOf(SasMode.EMOJI, SasMode.DECIMAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun state(): SasTransactionState
|
||||||
|
|
||||||
|
override fun isSuccessful() = state() is SasTransactionState.Done
|
||||||
|
|
||||||
fun supportsEmoji(): Boolean
|
fun supportsEmoji(): Boolean
|
||||||
|
|
||||||
fun getEmojiCodeRepresentation(): List<EmojiRepresentation>
|
fun getEmojiCodeRepresentation(): List<EmojiRepresentation>
|
||||||
|
@ -23,8 +23,8 @@ sealed class VerificationEvent(val transactionId: String) {
|
|||||||
data class TransactionUpdated(val transaction: VerificationTransaction) : VerificationEvent(transaction.transactionId)
|
data class TransactionUpdated(val transaction: VerificationTransaction) : VerificationEvent(transaction.transactionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VerificationEvent.getRequest() : PendingVerificationRequest? {
|
fun VerificationEvent.getRequest(): PendingVerificationRequest? {
|
||||||
return when(this) {
|
return when (this) {
|
||||||
is VerificationEvent.RequestAdded -> this.request
|
is VerificationEvent.RequestAdded -> this.request
|
||||||
is VerificationEvent.RequestUpdated -> this.request
|
is VerificationEvent.RequestUpdated -> this.request
|
||||||
is VerificationEvent.TransactionAdded -> null
|
is VerificationEvent.TransactionAdded -> null
|
||||||
@ -32,12 +32,11 @@ fun VerificationEvent.getRequest() : PendingVerificationRequest? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VerificationEvent.getTransaction() : VerificationTransaction? {
|
fun VerificationEvent.getTransaction(): VerificationTransaction? {
|
||||||
return when(this) {
|
return when (this) {
|
||||||
is VerificationEvent.RequestAdded -> null
|
is VerificationEvent.RequestAdded -> null
|
||||||
is VerificationEvent.RequestUpdated -> null
|
is VerificationEvent.RequestUpdated -> null
|
||||||
is VerificationEvent.TransactionAdded -> this.transaction
|
is VerificationEvent.TransactionAdded -> this.transaction
|
||||||
is VerificationEvent.TransactionUpdated -> this.transaction
|
is VerificationEvent.TransactionUpdated -> this.transaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@ package org.matrix.android.sdk.api.session.crypto.verification
|
|||||||
|
|
||||||
interface VerificationTransaction {
|
interface VerificationTransaction {
|
||||||
|
|
||||||
val state: VerificationTxState
|
|
||||||
|
|
||||||
val method: VerificationMethod
|
val method: VerificationMethod
|
||||||
|
|
||||||
val transactionId: String
|
val transactionId: String
|
||||||
@ -37,4 +35,6 @@ interface VerificationTransaction {
|
|||||||
suspend fun cancel(code: CancelCode)
|
suspend fun cancel(code: CancelCode)
|
||||||
|
|
||||||
fun isToDeviceTransport(): Boolean
|
fun isToDeviceTransport(): Boolean
|
||||||
|
|
||||||
|
fun isSuccessful(): Boolean
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,35 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.session.crypto.verification
|
package org.matrix.android.sdk.api.session.crypto.verification
|
||||||
|
|
||||||
|
sealed class SasTransactionState {
|
||||||
|
|
||||||
|
object None : SasTransactionState()
|
||||||
|
|
||||||
|
// I wend a start
|
||||||
|
object SasStarted : SasTransactionState()
|
||||||
|
|
||||||
|
// I received a start and it was accepted
|
||||||
|
object SasAccepted : SasTransactionState()
|
||||||
|
|
||||||
|
// I received an accept and sent my key
|
||||||
|
object SasKeySent : SasTransactionState()
|
||||||
|
|
||||||
|
// Keys exchanged and code ready to be shared
|
||||||
|
object SasShortCodeReady : SasTransactionState()
|
||||||
|
|
||||||
|
// I received the other Mac, but might have not yet confirmed the short code
|
||||||
|
// at that time (other side already confirmed)
|
||||||
|
data class SasMacReceived(val codeConfirmed: Boolean) : SasTransactionState()
|
||||||
|
|
||||||
|
// I confirmed the code and sent my mac
|
||||||
|
object SasMacSent : SasTransactionState()
|
||||||
|
|
||||||
|
// I am done, waiting for other Done
|
||||||
|
data class Done(val otherDone: Boolean) : SasTransactionState()
|
||||||
|
|
||||||
|
data class Cancelled(val cancelCode: CancelCode, val byMe: Boolean) : SasTransactionState()
|
||||||
|
}
|
||||||
|
|
||||||
sealed class VerificationTxState {
|
sealed class VerificationTxState {
|
||||||
/**
|
/**
|
||||||
* Uninitialized state.
|
* Uninitialized state.
|
||||||
@ -42,24 +71,24 @@ sealed class VerificationTxState {
|
|||||||
// object MacSent : VerificationSasTxState()
|
// object MacSent : VerificationSasTxState()
|
||||||
// object Verifying : VerificationSasTxState()
|
// object Verifying : VerificationSasTxState()
|
||||||
|
|
||||||
// I wend a start
|
// // I wend a start
|
||||||
object SasStarted : VerificationSasTxState()
|
// object SasStarted : VerificationSasTxState()
|
||||||
|
//
|
||||||
// I received a start and it was accepted
|
// // I received a start and it was accepted
|
||||||
object SasAccepted : VerificationSasTxState()
|
// object SasAccepted : VerificationSasTxState()
|
||||||
|
//
|
||||||
// I received an accept and sent my key
|
// // I received an accept and sent my key
|
||||||
object SasKeySent : VerificationSasTxState()
|
// object SasKeySent : VerificationSasTxState()
|
||||||
|
//
|
||||||
// Keys exchanged and code ready to be shared
|
// // Keys exchanged and code ready to be shared
|
||||||
object SasShortCodeReady : VerificationSasTxState()
|
// object SasShortCodeReady : VerificationSasTxState()
|
||||||
|
//
|
||||||
// I received the other Mac, but might have not yet confirmed the short code
|
// // I received the other Mac, but might have not yet confirmed the short code
|
||||||
// at that time (other side already confirmed)
|
// // at that time (other side already confirmed)
|
||||||
data class SasMacReceived(val codeConfirmed: Boolean) : VerificationSasTxState()
|
// data class SasMacReceived(val codeConfirmed: Boolean) : VerificationSasTxState()
|
||||||
|
//
|
||||||
// I confirmed the code and sent my mac
|
// // I confirmed the code and sent my mac
|
||||||
object SasMacSent : VerificationSasTxState()
|
// object SasMacSent : VerificationSasTxState()
|
||||||
|
|
||||||
// I am done, waiting for other Done
|
// I am done, waiting for other Done
|
||||||
data class Done(val otherDone: Boolean) : VerificationSasTxState()
|
data class Done(val otherDone: Boolean) : VerificationSasTxState()
|
||||||
@ -67,13 +96,13 @@ sealed class VerificationTxState {
|
|||||||
/**
|
/**
|
||||||
* Specific for QR code.
|
* Specific for QR code.
|
||||||
*/
|
*/
|
||||||
abstract class VerificationQrTxState : VerificationTxState()
|
// abstract class VerificationQrTxState : VerificationTxState()
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Will be used to ask the user if the other user has correctly scanned.
|
// * Will be used to ask the user if the other user has correctly scanned.
|
||||||
*/
|
// */
|
||||||
object QrScannedByOther : VerificationQrTxState()
|
// object QrScannedByOther : VerificationQrTxState()
|
||||||
object WaitingOtherReciprocateConfirm : VerificationQrTxState()
|
// object WaitingOtherReciprocateConfirm : VerificationQrTxState()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminal states.
|
* Terminal states.
|
||||||
|
@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.crypto.verification
|
|||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.IVerificationRequest
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
|
@ -31,9 +31,6 @@ import im.vector.app.features.createdirect.CreateDirectRoomViewModel
|
|||||||
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupSettingsViewModel
|
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupSettingsViewModel
|
||||||
import im.vector.app.features.crypto.quads.SharedSecureStorageViewModel
|
import im.vector.app.features.crypto.quads.SharedSecureStorageViewModel
|
||||||
import im.vector.app.features.crypto.recover.BootstrapSharedViewModel
|
import im.vector.app.features.crypto.recover.BootstrapSharedViewModel
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
|
||||||
import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodViewModel
|
|
||||||
import im.vector.app.features.crypto.verification.emoji.VerificationEmojiCodeViewModel
|
|
||||||
import im.vector.app.features.crypto.verification.user.UserVerificationViewModel
|
import im.vector.app.features.crypto.verification.user.UserVerificationViewModel
|
||||||
import im.vector.app.features.devtools.RoomDevToolViewModel
|
import im.vector.app.features.devtools.RoomDevToolViewModel
|
||||||
import im.vector.app.features.discovery.DiscoverySettingsViewModel
|
import im.vector.app.features.discovery.DiscoverySettingsViewModel
|
||||||
@ -512,15 +509,10 @@ interface MavericksViewModelModule {
|
|||||||
@MavericksViewModelKey(MessageActionsViewModel::class)
|
@MavericksViewModelKey(MessageActionsViewModel::class)
|
||||||
fun messageActionsViewModelFactory(factory: MessageActionsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
fun messageActionsViewModelFactory(factory: MessageActionsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
@Binds
|
// @Binds
|
||||||
@IntoMap
|
// @IntoMap
|
||||||
@MavericksViewModelKey(VerificationChooseMethodViewModel::class)
|
// @MavericksViewModelKey(VerificationChooseMethodViewModel::class)
|
||||||
fun verificationChooseMethodViewModelFactory(factory: VerificationChooseMethodViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
// fun verificationChooseMethodViewModelFactory(factory: VerificationChooseMethodViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@MavericksViewModelKey(VerificationEmojiCodeViewModel::class)
|
|
||||||
fun verificationEmojiCodeViewModelFactory(factory: VerificationEmojiCodeViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ -592,11 +584,10 @@ interface MavericksViewModelModule {
|
|||||||
@MavericksViewModelKey(BootstrapSharedViewModel::class)
|
@MavericksViewModelKey(BootstrapSharedViewModel::class)
|
||||||
fun bootstrapSharedViewModelFactory(factory: BootstrapSharedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
fun bootstrapSharedViewModelFactory(factory: BootstrapSharedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
@Binds
|
// @Binds
|
||||||
@IntoMap
|
// @IntoMap
|
||||||
@MavericksViewModelKey(VerificationBottomSheetViewModel::class)
|
// @MavericksViewModelKey(VerificationBottomSheetViewModel::class)
|
||||||
fun verificationBottomSheetViewModelFactory(factory: VerificationBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
// fun verificationBottomSheetViewModelFactory(factory: VerificationBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
@ -25,7 +25,6 @@ import im.vector.app.features.popup.PopupAlertManager
|
|||||||
import im.vector.app.features.session.coroutineScope
|
import im.vector.app.features.session.coroutineScope
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.flow.cancellable
|
import kotlinx.coroutines.flow.cancellable
|
||||||
@ -39,11 +38,11 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
|||||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
|
import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.SecretShareRequest
|
import org.matrix.android.sdk.api.session.crypto.model.SecretShareRequest
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.SasTransactionState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -275,8 +274,8 @@ class KeyRequestHandler @Inject constructor(
|
|||||||
|
|
||||||
override fun transactionUpdated(tx: VerificationTransaction) {
|
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||||
if (tx is SasVerificationTransaction) {
|
if (tx is SasVerificationTransaction) {
|
||||||
val state = tx.state
|
val state = tx.state()
|
||||||
if (state == VerificationTxState.Verified) {
|
if (state is SasTransactionState.Done) {
|
||||||
// ok it's verified, see if we have key request for that
|
// ok it's verified, see if we have key request for that
|
||||||
shareAllSessions("${tx.otherDeviceId}${tx.otherUserId}")
|
shareAllSessions("${tx.otherDeviceId}${tx.otherUserId}")
|
||||||
popupAlertManager.cancelAlert("ikr_${tx.otherDeviceId}${tx.otherUserId}")
|
popupAlertManager.cancelAlert("ikr_${tx.otherDeviceId}${tx.otherUserId}")
|
||||||
|
@ -37,10 +37,11 @@ import kotlinx.coroutines.launch
|
|||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.SasTransactionState
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import org.matrix.android.sdk.api.session.getUserOrDefault
|
import org.matrix.android.sdk.api.session.getUserOrDefault
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -89,8 +90,9 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
// TODO maybe check also if
|
// TODO maybe check also if
|
||||||
val uid = "kvr_${tx.transactionId}"
|
val uid = "kvr_${tx.transactionId}"
|
||||||
// TODO we don't have that anymore? as it has to be requested first?
|
// TODO we don't have that anymore? as it has to be requested first?
|
||||||
when (tx.state) {
|
if (tx !is SasVerificationTransaction) return
|
||||||
is VerificationTxState.SasStarted -> {
|
when (tx.state()) {
|
||||||
|
is SasTransactionState.SasStarted -> {
|
||||||
// Add a notification for every incoming request
|
// Add a notification for every incoming request
|
||||||
// val user = session.getUserOrDefault(tx.otherUserId).toMatrixItem()
|
// val user = session.getUserOrDefault(tx.otherUserId).toMatrixItem()
|
||||||
// val name = user.getBestName()
|
// val name = user.getBestName()
|
||||||
@ -139,7 +141,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
// }
|
// }
|
||||||
// popupAlertManager.postVectorAlert(alert)
|
// popupAlertManager.postVectorAlert(alert)
|
||||||
}
|
}
|
||||||
is VerificationTxState.TerminalTxState -> {
|
is SasTransactionState.Done -> {
|
||||||
// cancel related notification
|
// cancel related notification
|
||||||
popupAlertManager.cancelAlert(uid)
|
popupAlertManager.cancelAlert(uid)
|
||||||
}
|
}
|
||||||
@ -186,7 +188,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
val roomId = pr.roomId
|
val roomId = pr.roomId
|
||||||
if (roomId.isNullOrBlank()) {
|
if (roomId.isNullOrBlank()) {
|
||||||
// TODO
|
// TODO
|
||||||
//it.navigator.waitSessionVerification(it)
|
// it.navigator.waitSessionVerification(it)
|
||||||
} else {
|
} else {
|
||||||
it.navigator.openRoom(
|
it.navigator.openRoom(
|
||||||
context = it,
|
context = it,
|
||||||
@ -213,9 +215,9 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
|
|
||||||
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
|
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
|
||||||
// If an incoming request is readied (by another device?) we should discard the alert
|
// If an incoming request is readied (by another device?) we should discard the alert
|
||||||
if (pr.isIncoming && (pr.state == EVerificationState.HandledByOtherSession
|
if (pr.isIncoming && (pr.state == EVerificationState.HandledByOtherSession ||
|
||||||
|| pr.state == EVerificationState.Started
|
pr.state == EVerificationState.Started ||
|
||||||
|| pr.state == EVerificationState.WeStarted)) {
|
pr.state == EVerificationState.WeStarted)) {
|
||||||
popupAlertManager.cancelAlert(uniqueIdForVerificationRequest(pr))
|
popupAlertManager.cancelAlert(uniqueIdForVerificationRequest(pr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,266 +1,228 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification
|
// package im.vector.app.features.crypto.verification
|
||||||
|
//
|
||||||
import android.app.Activity
|
// import android.app.Activity
|
||||||
import android.app.Dialog
|
// import android.app.Dialog
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.os.Parcelable
|
// import android.os.Parcelable
|
||||||
import android.view.KeyEvent
|
// import android.view.KeyEvent
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
// import androidx.fragment.app.Fragment
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
// import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
// import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.commitTransaction
|
// import im.vector.app.core.extensions.commitTransaction
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
// import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.extensions.toMvRxBundle
|
// import im.vector.app.core.extensions.toMvRxBundle
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
// import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
// import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationBinding
|
// import im.vector.app.databinding.BottomSheetVerificationBinding
|
||||||
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
|
// import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
|
||||||
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
// import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
||||||
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
|
// import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
|
||||||
import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodFragment
|
// import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodFragment
|
||||||
import im.vector.app.features.crypto.verification.conclusion.VerificationConclusionFragment
|
// import im.vector.app.features.crypto.verification.conclusion.VerificationConclusionFragment
|
||||||
import im.vector.app.features.crypto.verification.emoji.VerificationEmojiCodeFragment
|
// import im.vector.app.features.crypto.verification.emoji.VerificationEmojiCodeFragment
|
||||||
import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQRWaitingFragment
|
// import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQRWaitingFragment
|
||||||
import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQrScannedByOtherFragment
|
// import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQrScannedByOtherFragment
|
||||||
import im.vector.app.features.crypto.verification.request.VerificationRequestFragment
|
// import im.vector.app.features.crypto.verification.request.VerificationRequestFragment
|
||||||
import im.vector.app.features.displayname.getBestName
|
// import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
// import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity
|
// import im.vector.app.features.settings.VectorSettingsActivity
|
||||||
import kotlinx.parcelize.Parcelize
|
// import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
// import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
// import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
|
// import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
|
// import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
// import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
// import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
// import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
||||||
import timber.log.Timber
|
// import timber.log.Timber
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
import kotlin.reflect.KClass
|
// import kotlin.reflect.KClass
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetVerificationBinding>() {
|
// class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetVerificationBinding>() {
|
||||||
|
//
|
||||||
@Parcelize
|
// @Parcelize
|
||||||
data class VerificationArgs(
|
// data class VerificationArgs(
|
||||||
val otherUserId: String,
|
// val otherUserId: String,
|
||||||
// might be null for self verification if there is no device to request to
|
// // might be null for self verification if there is no device to request to
|
||||||
// in this case you could use 4S (or reset all)
|
// // in this case you could use 4S (or reset all)
|
||||||
val verificationId: String?,
|
// val verificationId: String?,
|
||||||
// val verificationLocalId: String? = null,
|
// // val verificationLocalId: String? = null,
|
||||||
val roomId: String? = null,
|
// val roomId: String? = null,
|
||||||
// Special mode where UX should show loading wheel until other session sends a request/tx
|
// // Special mode where UX should show loading wheel until other session sends a request/tx
|
||||||
val selfVerificationMode: Boolean = false
|
// val selfVerificationMode: Boolean = false
|
||||||
) : Parcelable
|
// ) : Parcelable
|
||||||
|
//
|
||||||
override val showExpanded = true
|
// override val showExpanded = true
|
||||||
|
//
|
||||||
@Inject
|
// @Inject
|
||||||
lateinit var avatarRenderer: AvatarRenderer
|
// lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
//
|
||||||
private val viewModel by fragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val viewModel by fragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationBinding {
|
||||||
return BottomSheetVerificationBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
init {
|
// init {
|
||||||
isCancelable = false
|
// isCancelable = false
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
|
//
|
||||||
viewModel.observeViewEvents {
|
// viewModel.observeViewEvents {
|
||||||
when (it) {
|
// when (it) {
|
||||||
is VerificationBottomSheetViewEvents.Dismiss -> dismiss()
|
// is VerificationBottomSheetViewEvents.Dismiss -> dismiss()
|
||||||
is VerificationBottomSheetViewEvents.AccessSecretStore -> {
|
// is VerificationBottomSheetViewEvents.AccessSecretStore -> {
|
||||||
secretStartForActivityResult.launch(
|
// secretStartForActivityResult.launch(
|
||||||
SharedSecureStorageActivity.newReadIntent(
|
// SharedSecureStorageActivity.newReadIntent(
|
||||||
requireContext(),
|
// requireContext(),
|
||||||
null, // use default key
|
// null, // use default key
|
||||||
listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME),
|
// listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME),
|
||||||
SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
|
// SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
is VerificationBottomSheetViewEvents.ModalError -> {
|
// is VerificationBottomSheetViewEvents.ModalError -> {
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
// MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(getString(R.string.dialog_title_error))
|
// .setTitle(getString(R.string.dialog_title_error))
|
||||||
.setMessage(it.errorMessage)
|
// .setMessage(it.errorMessage)
|
||||||
.setCancelable(false)
|
// .setCancelable(false)
|
||||||
.setPositiveButton(R.string.ok, null)
|
// .setPositiveButton(R.string.ok, null)
|
||||||
.show()
|
// .show()
|
||||||
Unit
|
// Unit
|
||||||
}
|
// }
|
||||||
VerificationBottomSheetViewEvents.GoToSettings -> {
|
// VerificationBottomSheetViewEvents.GoToSettings -> {
|
||||||
dismiss()
|
// dismiss()
|
||||||
(activity as? VectorBaseActivity<*>)?.let { activity ->
|
// (activity as? VectorBaseActivity<*>)?.let { activity ->
|
||||||
activity.navigator.openSettings(activity, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY)
|
// activity.navigator.openSettings(activity, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
// override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
return super.onCreateDialog(savedInstanceState).apply {
|
// return super.onCreateDialog(savedInstanceState).apply {
|
||||||
setOnKeyListener { _, keyCode, keyEvent ->
|
// setOnKeyListener { _, keyCode, keyEvent ->
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
|
// if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
|
||||||
viewModel.queryCancel()
|
// viewModel.queryCancel()
|
||||||
true
|
// true
|
||||||
} else {
|
// } else {
|
||||||
false
|
// false
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private val secretStartForActivityResult = registerStartForActivityResult { activityResult ->
|
// private val secretStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
// if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||||
val result = activityResult.data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
|
// val result = activityResult.data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
|
||||||
val reset = activityResult.data?.getBooleanExtra(SharedSecureStorageActivity.EXTRA_DATA_RESET, false) ?: false
|
// val reset = activityResult.data?.getBooleanExtra(SharedSecureStorageActivity.EXTRA_DATA_RESET, false) ?: false
|
||||||
if (result != null) {
|
// if (result != null) {
|
||||||
viewModel.handle(VerificationAction.GotResultFromSsss(result, SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS))
|
// viewModel.handle(VerificationAction.GotResultFromSsss(result, SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS))
|
||||||
} else if (reset) {
|
// } else if (reset) {
|
||||||
// all have been reset, so we are verified?
|
// // all have been reset, so we are verified?
|
||||||
viewModel.handle(VerificationAction.SecuredStorageHasBeenReset)
|
// viewModel.handle(VerificationAction.SecuredStorageHasBeenReset)
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
viewModel.handle(VerificationAction.CancelledFromSsss)
|
// viewModel.handle(VerificationAction.CancelledFromSsss)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
// override fun invalidate() = withState(viewModel) { state ->
|
||||||
avatarRenderer.render(state.otherUserMxItem, views.otherUserAvatarImageView)
|
// avatarRenderer.render(state.otherUserMxItem, views.otherUserAvatarImageView)
|
||||||
if (state.isMe) {
|
// if (state.isMe) {
|
||||||
if (state.sasTransactionState == VerificationTxState.Verified ||
|
// if (state.sasTransactionState == VerificationTxState.Verified ||
|
||||||
state.qrTransactionState == VerificationTxState.Verified ||
|
// state.qrTransactionState == VerificationTxState.Verified ||
|
||||||
state.verifiedFromPrivateKeys) {
|
// state.verifiedFromPrivateKeys) {
|
||||||
views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
|
// views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
|
||||||
} else {
|
// } else {
|
||||||
views.otherUserShield.render(RoomEncryptionTrustLevel.Warning)
|
// views.otherUserShield.render(RoomEncryptionTrustLevel.Warning)
|
||||||
}
|
// }
|
||||||
views.otherUserNameText.text = getString(
|
// views.otherUserNameText.text = getString(
|
||||||
if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
|
// if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
|
||||||
)
|
// )
|
||||||
} else {
|
// } else {
|
||||||
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
|
// if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
|
||||||
views.otherUserNameText.text = getString(R.string.verification_verified_user, state.otherUserMxItem.getBestName())
|
// views.otherUserNameText.text = getString(R.string.verification_verified_user, state.otherUserMxItem.getBestName())
|
||||||
views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
|
// views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
|
||||||
} else {
|
// } else {
|
||||||
views.otherUserNameText.text = getString(R.string.verification_verify_user, state.otherUserMxItem.getBestName())
|
// views.otherUserNameText.text = getString(R.string.verification_verify_user, state.otherUserMxItem.getBestName())
|
||||||
views.otherUserShield.render(null)
|
// views.otherUserShield.render(null)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.quadSHasBeenReset) {
|
// if (state.quadSHasBeenReset) {
|
||||||
showFragment(
|
// showFragment(
|
||||||
VerificationConclusionFragment::class,
|
// VerificationConclusionFragment::class,
|
||||||
VerificationConclusionFragment.Args(
|
// VerificationConclusionFragment.Args(
|
||||||
isSuccessFull = true,
|
// isSuccessFull = true,
|
||||||
isMe = true,
|
// isMe = true,
|
||||||
cancelReason = null
|
// cancelReason = null
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
return@withState
|
// return@withState
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.userThinkItsNotHim) {
|
// if (state.userThinkItsNotHim) {
|
||||||
views.otherUserNameText.text = getString(R.string.dialog_title_warning)
|
// views.otherUserNameText.text = getString(R.string.dialog_title_warning)
|
||||||
showFragment(VerificationNotMeFragment::class)
|
// showFragment(VerificationNotMeFragment::class)
|
||||||
return@withState
|
// return@withState
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.userWantsToCancel) {
|
// if (state.userWantsToCancel) {
|
||||||
views.otherUserNameText.text = getString(R.string.are_you_sure)
|
// views.otherUserNameText.text = getString(R.string.are_you_sure)
|
||||||
showFragment(VerificationCancelFragment::class)
|
// showFragment(VerificationCancelFragment::class)
|
||||||
return@withState
|
// return@withState
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.selfVerificationMode && state.verifyingFrom4S) {
|
// if (state.selfVerificationMode && state.verifyingFrom4S) {
|
||||||
showFragment(QuadSLoadingFragment::class)
|
// showFragment(QuadSLoadingFragment::class)
|
||||||
return@withState
|
// return@withState
|
||||||
}
|
// }
|
||||||
if (state.selfVerificationMode && state.verifiedFromPrivateKeys) {
|
// if (state.selfVerificationMode && state.verifiedFromPrivateKeys) {
|
||||||
showFragment(
|
// showFragment(
|
||||||
VerificationConclusionFragment::class,
|
// VerificationConclusionFragment::class,
|
||||||
VerificationConclusionFragment.Args(true, null, state.isMe)
|
// VerificationConclusionFragment.Args(true, null, state.isMe)
|
||||||
)
|
// )
|
||||||
return@withState
|
// return@withState
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Did the request result in a SAS transaction?
|
// // Did the request result in a SAS transaction?
|
||||||
if (state.sasTransactionState != null) {
|
// if (state.sasTransactionState != null) {
|
||||||
when (state.sasTransactionState) {
|
// when (state.sasTransactionState) {
|
||||||
|
//
|
||||||
VerificationTxState.None,
|
// VerificationTxState.None,
|
||||||
VerificationTxState.SasStarted,
|
// VerificationTxState.SasStarted,
|
||||||
VerificationTxState.SasKeySent,
|
// VerificationTxState.SasKeySent,
|
||||||
VerificationTxState.SasShortCodeReady,
|
// VerificationTxState.SasShortCodeReady,
|
||||||
VerificationTxState.SasMacSent,
|
// VerificationTxState.SasMacSent,
|
||||||
is VerificationTxState.SasMacReceived,
|
// is VerificationTxState.SasMacReceived,
|
||||||
VerificationTxState.SasAccepted -> {
|
// VerificationTxState.SasAccepted -> {
|
||||||
showFragment(
|
|
||||||
VerificationEmojiCodeFragment::class,
|
|
||||||
VerificationArgs(
|
|
||||||
state.otherUserId,
|
|
||||||
// If it was outgoing it.transaction id would be null, but the pending request
|
|
||||||
// would be updated (from localId to txId)
|
|
||||||
state.pendingRequest.invoke()?.transactionId ?: state.transactionId
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is VerificationTxState.Verified -> {
|
|
||||||
showFragment(
|
|
||||||
VerificationConclusionFragment::class,
|
|
||||||
VerificationConclusionFragment.Args(true, null, state.isMe)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is VerificationTxState.Cancelled -> {
|
|
||||||
showFragment(
|
|
||||||
VerificationConclusionFragment::class,
|
|
||||||
VerificationConclusionFragment.Args(false, state.sasTransactionState.cancelCode.value, state.isMe)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> Unit
|
|
||||||
// is VerificationTxState.None,
|
|
||||||
// is VerificationTxState.SendingStart,
|
|
||||||
// is VerificationTxState.Started,
|
|
||||||
// is VerificationTxState.OnStarted,
|
|
||||||
// is VerificationTxState.SendingAccept,
|
|
||||||
// is VerificationTxState.Accepted,
|
|
||||||
// is VerificationTxState.OnAccepted,
|
|
||||||
// is VerificationTxState.SendingKey,
|
|
||||||
// is VerificationTxState.KeySent,
|
|
||||||
// is VerificationTxState.OnKeyReceived,
|
|
||||||
// is VerificationTxState.ShortCodeReady,
|
|
||||||
// is VerificationTxState.ShortCodeAccepted,
|
|
||||||
// is VerificationTxState.SendingMac,
|
|
||||||
// is VerificationTxState.MacSent,
|
|
||||||
// is VerificationTxState.Verifying -> {
|
|
||||||
// showFragment(
|
// showFragment(
|
||||||
// VerificationEmojiCodeFragment::class,
|
// VerificationEmojiCodeFragment::class,
|
||||||
// VerificationArgs(
|
// VerificationArgs(
|
||||||
@ -284,156 +246,194 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
|
|||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
// else -> Unit
|
// else -> Unit
|
||||||
}
|
// // is VerificationTxState.None,
|
||||||
|
// // is VerificationTxState.SendingStart,
|
||||||
return@withState
|
// // is VerificationTxState.Started,
|
||||||
}
|
// // is VerificationTxState.OnStarted,
|
||||||
|
// // is VerificationTxState.SendingAccept,
|
||||||
when (state.qrTransactionState) {
|
// // is VerificationTxState.Accepted,
|
||||||
is VerificationTxState.QrScannedByOther -> {
|
// // is VerificationTxState.OnAccepted,
|
||||||
showFragment(VerificationQrScannedByOtherFragment::class)
|
// // is VerificationTxState.SendingKey,
|
||||||
return@withState
|
// // is VerificationTxState.KeySent,
|
||||||
}
|
// // is VerificationTxState.OnKeyReceived,
|
||||||
//TODO
|
// // is VerificationTxState.ShortCodeReady,
|
||||||
// is VerificationTxState.Started,
|
// // is VerificationTxState.ShortCodeAccepted,
|
||||||
is VerificationTxState.WaitingOtherReciprocateConfirm -> {
|
// // is VerificationTxState.SendingMac,
|
||||||
showFragment(
|
// // is VerificationTxState.MacSent,
|
||||||
VerificationQRWaitingFragment::class,
|
// // is VerificationTxState.Verifying -> {
|
||||||
VerificationQRWaitingFragment.Args(
|
// // showFragment(
|
||||||
isMe = state.isMe,
|
// // VerificationEmojiCodeFragment::class,
|
||||||
otherUserName = state.otherUserMxItem.getBestName()
|
// // VerificationArgs(
|
||||||
)
|
// // state.otherUserId,
|
||||||
)
|
// // // If it was outgoing it.transaction id would be null, but the pending request
|
||||||
return@withState
|
// // // would be updated (from localId to txId)
|
||||||
}
|
// // state.pendingRequest.invoke()?.transactionId ?: state.transactionId
|
||||||
is VerificationTxState.Verified -> {
|
// // )
|
||||||
showFragment(
|
// // )
|
||||||
VerificationConclusionFragment::class,
|
// // }
|
||||||
VerificationConclusionFragment.Args(true, null, state.isMe)
|
// // is VerificationTxState.Verified -> {
|
||||||
)
|
// // showFragment(
|
||||||
return@withState
|
// // VerificationConclusionFragment::class,
|
||||||
}
|
// // VerificationConclusionFragment.Args(true, null, state.isMe)
|
||||||
is VerificationTxState.Cancelled -> {
|
// // )
|
||||||
showFragment(
|
// // }
|
||||||
VerificationConclusionFragment::class,
|
// // is VerificationTxState.Cancelled -> {
|
||||||
VerificationConclusionFragment.Args(false, state.qrTransactionState.cancelCode.value, state.isMe)
|
// // showFragment(
|
||||||
)
|
// // VerificationConclusionFragment::class,
|
||||||
return@withState
|
// // VerificationConclusionFragment.Args(false, state.sasTransactionState.cancelCode.value, state.isMe)
|
||||||
}
|
// // )
|
||||||
else -> Unit
|
// // }
|
||||||
}
|
// // else -> Unit
|
||||||
|
// }
|
||||||
// At this point there is no SAS transaction for this request
|
//
|
||||||
|
// return@withState
|
||||||
// Transaction has not yet started
|
// }
|
||||||
if (state.pendingRequest.invoke()?.cancelConclusion != null) {
|
//
|
||||||
// The request has been declined, we should dismiss
|
// when (state.qrTransactionState) {
|
||||||
views.otherUserNameText.text = getString(R.string.verification_cancelled)
|
// is VerificationTxState.QrScannedByOther -> {
|
||||||
showFragment(
|
// showFragment(VerificationQrScannedByOtherFragment::class)
|
||||||
VerificationConclusionFragment::class,
|
// return@withState
|
||||||
VerificationConclusionFragment.Args(
|
// }
|
||||||
isSuccessFull = false,
|
// //TODO
|
||||||
cancelReason = state.pendingRequest.invoke()?.cancelConclusion?.value ?: CancelCode.User.value,
|
// // is VerificationTxState.Started,
|
||||||
isMe = state.isMe
|
// is VerificationTxState.WaitingOtherReciprocateConfirm -> {
|
||||||
)
|
// showFragment(
|
||||||
)
|
// VerificationQRWaitingFragment::class,
|
||||||
return@withState
|
// VerificationQRWaitingFragment.Args(
|
||||||
}
|
// isMe = state.isMe,
|
||||||
|
// otherUserName = state.otherUserMxItem.getBestName()
|
||||||
// If it's an outgoing
|
// )
|
||||||
if (state.pendingRequest.invoke() == null || state.pendingRequest.invoke()?.isIncoming == false || state.selfVerificationMode) {
|
// )
|
||||||
Timber.v("## SAS show bottom sheet for outgoing request")
|
// return@withState
|
||||||
if (state.pendingRequest.invoke()?.state == EVerificationState.Ready) {
|
// }
|
||||||
Timber.v("## SAS show bottom sheet for outgoing and ready request")
|
// is VerificationTxState.Verified -> {
|
||||||
// Show choose method fragment with waiting
|
// showFragment(
|
||||||
showFragment(
|
// VerificationConclusionFragment::class,
|
||||||
VerificationChooseMethodFragment::class,
|
// VerificationConclusionFragment.Args(true, null, state.isMe)
|
||||||
VerificationArgs(
|
// )
|
||||||
otherUserId = state.otherUserId,
|
// return@withState
|
||||||
verificationId = state.pendingRequest.invoke()?.transactionId
|
// }
|
||||||
)
|
// is VerificationTxState.Cancelled -> {
|
||||||
)
|
// showFragment(
|
||||||
} else {
|
// VerificationConclusionFragment::class,
|
||||||
// Stay on the start fragment
|
// VerificationConclusionFragment.Args(false, state.qrTransactionState.cancelCode.value, state.isMe)
|
||||||
showFragment(
|
// )
|
||||||
VerificationRequestFragment::class,
|
// return@withState
|
||||||
VerificationArgs(
|
// }
|
||||||
otherUserId = state.otherUserId,
|
// else -> Unit
|
||||||
verificationId = state.pendingRequest.invoke()?.transactionId,
|
// }
|
||||||
)
|
//
|
||||||
)
|
// // At this point there is no SAS transaction for this request
|
||||||
}
|
//
|
||||||
} else if (state.pendingRequest.invoke()?.isIncoming == true) {
|
// // Transaction has not yet started
|
||||||
Timber.v("## SAS show bottom sheet for Incoming request")
|
// if (state.pendingRequest.invoke()?.cancelConclusion != null) {
|
||||||
// For incoming we can switch to choose method because ready is being sent or already sent
|
// // The request has been declined, we should dismiss
|
||||||
showFragment(
|
// views.otherUserNameText.text = getString(R.string.verification_cancelled)
|
||||||
VerificationChooseMethodFragment::class,
|
// showFragment(
|
||||||
VerificationArgs(
|
// VerificationConclusionFragment::class,
|
||||||
otherUserId = state.otherUserId,
|
// VerificationConclusionFragment.Args(
|
||||||
verificationId = state.pendingRequest.invoke()?.transactionId
|
// isSuccessFull = false,
|
||||||
)
|
// cancelReason = state.pendingRequest.invoke()?.cancelConclusion?.value ?: CancelCode.User.value,
|
||||||
)
|
// isMe = state.isMe
|
||||||
}
|
// )
|
||||||
super.invalidate()
|
// )
|
||||||
}
|
// return@withState
|
||||||
|
// }
|
||||||
private fun showFragment(fragmentClass: KClass<out Fragment>, argsParcelable: Parcelable? = null) {
|
//
|
||||||
if (childFragmentManager.findFragmentByTag(fragmentClass.simpleName) == null) {
|
// // If it's an outgoing
|
||||||
childFragmentManager.commitTransaction {
|
// if (state.pendingRequest.invoke() == null || state.pendingRequest.invoke()?.isIncoming == false || state.selfVerificationMode) {
|
||||||
replace(
|
// Timber.v("## SAS show bottom sheet for outgoing request")
|
||||||
R.id.bottomSheetFragmentContainer,
|
// if (state.pendingRequest.invoke()?.state == EVerificationState.Ready) {
|
||||||
fragmentClass.java,
|
// Timber.v("## SAS show bottom sheet for outgoing and ready request")
|
||||||
argsParcelable?.toMvRxBundle(),
|
// // Show choose method fragment with waiting
|
||||||
fragmentClass.simpleName
|
// showFragment(
|
||||||
)
|
// VerificationChooseMethodFragment::class,
|
||||||
}
|
// VerificationArgs(
|
||||||
}
|
// otherUserId = state.otherUserId,
|
||||||
}
|
// verificationId = state.pendingRequest.invoke()?.transactionId
|
||||||
|
// )
|
||||||
companion object {
|
// )
|
||||||
fun withArgs(otherUserId: String, transactionId: String): VerificationBottomSheet {
|
// } else {
|
||||||
return VerificationBottomSheet().apply {
|
// // Stay on the start fragment
|
||||||
setArguments(
|
// showFragment(
|
||||||
VerificationArgs(
|
// VerificationRequestFragment::class,
|
||||||
otherUserId = otherUserId,
|
// VerificationArgs(
|
||||||
verificationId = transactionId,
|
// otherUserId = state.otherUserId,
|
||||||
)
|
// verificationId = state.pendingRequest.invoke()?.transactionId,
|
||||||
)
|
// )
|
||||||
}
|
// )
|
||||||
}
|
// }
|
||||||
|
// } else if (state.pendingRequest.invoke()?.isIncoming == true) {
|
||||||
// fun forSelfVerification(session: Session): VerificationBottomSheet {
|
// Timber.v("## SAS show bottom sheet for Incoming request")
|
||||||
|
// // For incoming we can switch to choose method because ready is being sent or already sent
|
||||||
|
// showFragment(
|
||||||
|
// VerificationChooseMethodFragment::class,
|
||||||
|
// VerificationArgs(
|
||||||
|
// otherUserId = state.otherUserId,
|
||||||
|
// verificationId = state.pendingRequest.invoke()?.transactionId
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// super.invalidate()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun showFragment(fragmentClass: KClass<out Fragment>, argsParcelable: Parcelable? = null) {
|
||||||
|
// if (childFragmentManager.findFragmentByTag(fragmentClass.simpleName) == null) {
|
||||||
|
// childFragmentManager.commitTransaction {
|
||||||
|
// replace(
|
||||||
|
// R.id.bottomSheetFragmentContainer,
|
||||||
|
// fragmentClass.java,
|
||||||
|
// argsParcelable?.toMvRxBundle(),
|
||||||
|
// fragmentClass.simpleName
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// companion object {
|
||||||
|
// fun withArgs(otherUserId: String, transactionId: String): VerificationBottomSheet {
|
||||||
// return VerificationBottomSheet().apply {
|
// return VerificationBottomSheet().apply {
|
||||||
// setArguments(
|
// setArguments(
|
||||||
// VerificationArgs(
|
// VerificationArgs(
|
||||||
// otherUserId = session.myUserId,
|
// otherUserId = otherUserId,
|
||||||
// selfVerificationMode = true
|
// verificationId = transactionId,
|
||||||
// )
|
// )
|
||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// fun forSelfVerification(session: Session, outgoingRequest: String): VerificationBottomSheet {
|
// // fun forSelfVerification(session: Session): VerificationBottomSheet {
|
||||||
// return VerificationBottomSheet().apply {
|
// // return VerificationBottomSheet().apply {
|
||||||
// setArguments(
|
// // setArguments(
|
||||||
// VerificationArgs(
|
// // VerificationArgs(
|
||||||
// otherUserId = session.myUserId,
|
// // otherUserId = session.myUserId,
|
||||||
// selfVerificationMode = true,
|
// // selfVerificationMode = true
|
||||||
// verificationId = outgoingRequest
|
// // )
|
||||||
// )
|
// // )
|
||||||
// )
|
// // }
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// // fun forSelfVerification(session: Session, outgoingRequest: String): VerificationBottomSheet {
|
||||||
|
// // return VerificationBottomSheet().apply {
|
||||||
|
// // setArguments(
|
||||||
|
// // VerificationArgs(
|
||||||
|
// // otherUserId = session.myUserId,
|
||||||
|
// // selfVerificationMode = true,
|
||||||
|
// // verificationId = outgoingRequest
|
||||||
|
// // )
|
||||||
|
// // )
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// // const val WAITING_SELF_VERIF_TAG: String = "WAITING_SELF_VERIF_TAG"
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// const val WAITING_SELF_VERIF_TAG: String = "WAITING_SELF_VERIF_TAG"
|
// // fun View.getParentCoordinatorLayout(): CoordinatorLayout? {
|
||||||
}
|
// // var current = this as? View
|
||||||
}
|
// // while (current != null) {
|
||||||
|
// // if (current is CoordinatorLayout) return current
|
||||||
// fun View.getParentCoordinatorLayout(): CoordinatorLayout? {
|
// // current = current.parent as? View
|
||||||
// var current = this as? View
|
// // }
|
||||||
// while (current != null) {
|
// // return null
|
||||||
// if (current is CoordinatorLayout) return current
|
// // }
|
||||||
// current = current.parent as? View
|
|
||||||
// }
|
|
||||||
// return null
|
|
||||||
// }
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,109 +1,109 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright (c) 2020 New Vector Ltd
|
// * Copyright (c) 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.cancel
|
// package im.vector.app.features.crypto.verification.cancel
|
||||||
|
//
|
||||||
import androidx.core.text.toSpannable
|
// import androidx.core.text.toSpannable
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
// import im.vector.app.core.utils.colorizeMatchingText
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.displayname.getBestName
|
// import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationCancelController @Inject constructor(
|
// class VerificationCancelController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider
|
// private val colorProvider: ColorProvider
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var listener: Listener? = null
|
// var listener: Listener? = null
|
||||||
|
//
|
||||||
private var viewState: VerificationBottomSheetViewState? = null
|
// private var viewState: VerificationBottomSheetViewState? = null
|
||||||
|
//
|
||||||
fun update(viewState: VerificationBottomSheetViewState) {
|
// fun update(viewState: VerificationBottomSheetViewState) {
|
||||||
this.viewState = viewState
|
// this.viewState = viewState
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val state = viewState ?: return
|
// val state = viewState ?: return
|
||||||
val host = this
|
// val host = this
|
||||||
if (state.isMe) {
|
// if (state.isMe) {
|
||||||
if (state.currentDeviceCanCrossSign) {
|
// if (state.currentDeviceCanCrossSign) {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verify_cancel_self_verification_from_trusted).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verify_cancel_self_verification_from_trusted).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verify_cancel_self_verification_from_untrusted).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verify_cancel_self_verification_from_untrusted).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
val otherUserID = state.otherUserId
|
// val otherUserID = state.otherUserId
|
||||||
val otherDisplayName = state.otherUserMxItem.getBestName()
|
// val otherDisplayName = state.otherUserMxItem.getBestName()
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(
|
// notice(
|
||||||
EpoxyCharSequence(
|
// EpoxyCharSequence(
|
||||||
host.stringProvider.getString(R.string.verify_cancel_other, otherDisplayName, otherUserID)
|
// host.stringProvider.getString(R.string.verify_cancel_other, otherDisplayName, otherUserID)
|
||||||
.toSpannable()
|
// .toSpannable()
|
||||||
.colorizeMatchingText(otherUserID, host.colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
|
// .colorizeMatchingText(otherUserID, host.colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("cancel")
|
// id("cancel")
|
||||||
title(host.stringProvider.getString(R.string.action_skip))
|
// title(host.stringProvider.getString(R.string.action_skip))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
listener { host.listener?.onTapCancel() }
|
// listener { host.listener?.onTapCancel() }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep1")
|
// id("sep1")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("continue")
|
// id("continue")
|
||||||
title(host.stringProvider.getString(R.string._continue))
|
// title(host.stringProvider.getString(R.string._continue))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
listener { host.listener?.onTapContinue() }
|
// listener { host.listener?.onTapContinue() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
interface Listener {
|
// interface Listener {
|
||||||
fun onTapCancel()
|
// fun onTapCancel()
|
||||||
fun onTapContinue()
|
// fun onTapContinue()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,73 +1,73 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright (c) 2020 New Vector Ltd
|
// * Copyright (c) 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.cancel
|
// package im.vector.app.features.crypto.verification.cancel
|
||||||
|
//
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.extensions.cleanup
|
// import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
// import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationCancelFragment :
|
// class VerificationCancelFragment :
|
||||||
VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
// VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
VerificationCancelController.Listener {
|
// VerificationCancelController.Listener {
|
||||||
|
//
|
||||||
@Inject lateinit var controller: VerificationCancelController
|
// @Inject lateinit var controller: VerificationCancelController
|
||||||
|
//
|
||||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
setupRecyclerView()
|
// setupRecyclerView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroyView() {
|
// override fun onDestroyView() {
|
||||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
// views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
// controller.listener = null
|
||||||
super.onDestroyView()
|
// super.onDestroyView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun setupRecyclerView() {
|
// private fun setupRecyclerView() {
|
||||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
// views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
// controller.listener = this
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
// override fun invalidate() = withState(viewModel) { state ->
|
||||||
controller.update(state)
|
// controller.update(state)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onTapCancel() {
|
// override fun onTapCancel() {
|
||||||
viewModel.confirmCancel()
|
// viewModel.confirmCancel()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onTapContinue() {
|
// override fun onTapContinue() {
|
||||||
viewModel.continueFromCancel()
|
// viewModel.continueFromCancel()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,84 +1,84 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright (c) 2020 New Vector Ltd
|
// * Copyright (c) 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.cancel
|
// package im.vector.app.features.crypto.verification.cancel
|
||||||
|
//
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.html.EventHtmlRenderer
|
// import im.vector.app.features.html.EventHtmlRenderer
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationNotMeController @Inject constructor(
|
// class VerificationNotMeController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider,
|
// private val colorProvider: ColorProvider,
|
||||||
private val eventHtmlRenderer: EventHtmlRenderer
|
// private val eventHtmlRenderer: EventHtmlRenderer
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var listener: Listener? = null
|
// var listener: Listener? = null
|
||||||
|
//
|
||||||
private var viewState: VerificationBottomSheetViewState? = null
|
// private var viewState: VerificationBottomSheetViewState? = null
|
||||||
|
//
|
||||||
fun update(viewState: VerificationBottomSheetViewState) {
|
// fun update(viewState: VerificationBottomSheetViewState) {
|
||||||
this.viewState = viewState
|
// this.viewState = viewState
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val host = this
|
// val host = this
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.eventHtmlRenderer.render(host.stringProvider.getString(R.string.verify_not_me_self_verification)).toEpoxyCharSequence())
|
// notice(host.eventHtmlRenderer.render(host.stringProvider.getString(R.string.verify_not_me_self_verification)).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("skip")
|
// id("skip")
|
||||||
title(host.stringProvider.getString(R.string.action_skip))
|
// title(host.stringProvider.getString(R.string.action_skip))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.onTapSkip() }
|
// listener { host.listener?.onTapSkip() }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep1")
|
// id("sep1")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("settings")
|
// id("settings")
|
||||||
title(host.stringProvider.getString(R.string.settings))
|
// title(host.stringProvider.getString(R.string.settings))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
listener { host.listener?.onTapSettings() }
|
// listener { host.listener?.onTapSettings() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
interface Listener {
|
// interface Listener {
|
||||||
fun onTapSkip()
|
// fun onTapSkip()
|
||||||
fun onTapSettings()
|
// fun onTapSettings()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,73 +1,73 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright (c) 2020 New Vector Ltd
|
// * Copyright (c) 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.cancel
|
// package im.vector.app.features.crypto.verification.cancel
|
||||||
|
//
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.extensions.cleanup
|
// import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
// import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationNotMeFragment :
|
// class VerificationNotMeFragment :
|
||||||
VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
// VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
VerificationNotMeController.Listener {
|
// VerificationNotMeController.Listener {
|
||||||
|
//
|
||||||
@Inject lateinit var controller: VerificationNotMeController
|
// @Inject lateinit var controller: VerificationNotMeController
|
||||||
|
//
|
||||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
setupRecyclerView()
|
// setupRecyclerView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroyView() {
|
// override fun onDestroyView() {
|
||||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
// views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
// controller.listener = null
|
||||||
super.onDestroyView()
|
// super.onDestroyView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun setupRecyclerView() {
|
// private fun setupRecyclerView() {
|
||||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
// views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
// controller.listener = this
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
// override fun invalidate() = withState(viewModel) { state ->
|
||||||
controller.update(state)
|
// controller.update(state)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onTapSkip() {
|
// override fun onTapSkip() {
|
||||||
viewModel.continueFromWasNotMe()
|
// viewModel.continueFromWasNotMe()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onTapSettings() {
|
// override fun onTapSettings() {
|
||||||
viewModel.goToSettings()
|
// viewModel.goToSettings()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,147 +1,147 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2020 New Vector Ltd
|
// * Copyright 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.choose
|
// package im.vector.app.features.crypto.verification.choose
|
||||||
|
//
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.ui.list.buttonPositiveDestructiveButtonBarItem
|
// import im.vector.app.core.ui.list.buttonPositiveDestructiveButtonBarItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationQrCodeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationQrCodeItem
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationChooseMethodController @Inject constructor(
|
// class VerificationChooseMethodController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider
|
// private val colorProvider: ColorProvider
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var listener: Listener? = null
|
// var listener: Listener? = null
|
||||||
|
//
|
||||||
private var viewState: VerificationChooseMethodViewState? = null
|
// private var viewState: VerificationChooseMethodViewState? = null
|
||||||
|
//
|
||||||
fun update(viewState: VerificationChooseMethodViewState) {
|
// fun update(viewState: VerificationChooseMethodViewState) {
|
||||||
this.viewState = viewState
|
// this.viewState = viewState
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val state = viewState ?: return
|
// val state = viewState ?: return
|
||||||
val host = this
|
// val host = this
|
||||||
|
//
|
||||||
if (state.otherCanScanQrCode || state.otherCanShowQrCode) {
|
// if (state.otherCanScanQrCode || state.otherCanShowQrCode) {
|
||||||
val scanCodeInstructions: String
|
// val scanCodeInstructions: String
|
||||||
val scanOtherCodeTitle: String
|
// val scanOtherCodeTitle: String
|
||||||
val compareEmojiSubtitle: String
|
// val compareEmojiSubtitle: String
|
||||||
if (state.isMe) {
|
// if (state.isMe) {
|
||||||
scanCodeInstructions = stringProvider.getString(R.string.verification_scan_self_notice)
|
// scanCodeInstructions = stringProvider.getString(R.string.verification_scan_self_notice)
|
||||||
scanOtherCodeTitle = stringProvider.getString(R.string.verification_scan_with_this_device)
|
// scanOtherCodeTitle = stringProvider.getString(R.string.verification_scan_with_this_device)
|
||||||
compareEmojiSubtitle = stringProvider.getString(R.string.verification_scan_self_emoji_subtitle)
|
// compareEmojiSubtitle = stringProvider.getString(R.string.verification_scan_self_emoji_subtitle)
|
||||||
} else {
|
// } else {
|
||||||
scanCodeInstructions = stringProvider.getString(R.string.verification_scan_notice)
|
// scanCodeInstructions = stringProvider.getString(R.string.verification_scan_notice)
|
||||||
scanOtherCodeTitle = stringProvider.getString(R.string.verification_scan_their_code)
|
// scanOtherCodeTitle = stringProvider.getString(R.string.verification_scan_their_code)
|
||||||
compareEmojiSubtitle = stringProvider.getString(R.string.verification_scan_emoji_subtitle)
|
// compareEmojiSubtitle = stringProvider.getString(R.string.verification_scan_emoji_subtitle)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(scanCodeInstructions.toEpoxyCharSequence())
|
// notice(scanCodeInstructions.toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.otherCanScanQrCode && !state.qrCodeText.isNullOrBlank()) {
|
// if (state.otherCanScanQrCode && !state.qrCodeText.isNullOrBlank()) {
|
||||||
bottomSheetVerificationQrCodeItem {
|
// bottomSheetVerificationQrCodeItem {
|
||||||
id("qr")
|
// id("qr")
|
||||||
data(state.qrCodeText)
|
// data(state.qrCodeText)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.otherCanShowQrCode) {
|
// if (state.otherCanShowQrCode) {
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("openCamera")
|
// id("openCamera")
|
||||||
title(scanOtherCodeTitle)
|
// title(scanOtherCodeTitle)
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
iconRes(R.drawable.ic_camera)
|
// iconRes(R.drawable.ic_camera)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
listener { host.listener?.openCamera() }
|
// listener { host.listener?.openCamera() }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep1")
|
// id("sep1")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("openEmoji")
|
// id("openEmoji")
|
||||||
title(host.stringProvider.getString(R.string.verification_scan_emoji_title))
|
// title(host.stringProvider.getString(R.string.verification_scan_emoji_title))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
subTitle(compareEmojiSubtitle)
|
// subTitle(compareEmojiSubtitle)
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.doVerifyBySas() }
|
// listener { host.listener?.doVerifyBySas() }
|
||||||
}
|
// }
|
||||||
} else if (state.sasModeAvailable) {
|
// } else if (state.sasModeAvailable) {
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("openEmoji")
|
// id("openEmoji")
|
||||||
title(host.stringProvider.getString(R.string.verification_no_scan_emoji_title))
|
// title(host.stringProvider.getString(R.string.verification_no_scan_emoji_title))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.doVerifyBySas() }
|
// listener { host.listener?.doVerifyBySas() }
|
||||||
}
|
// }
|
||||||
} else if (!state.isReadySent) {
|
// } else if (!state.isReadySent) {
|
||||||
// a bit of a special case, if you tapped on the timeline cell but not on a button
|
// // a bit of a special case, if you tapped on the timeline cell but not on a button
|
||||||
buttonPositiveDestructiveButtonBarItem {
|
// buttonPositiveDestructiveButtonBarItem {
|
||||||
id("accept_decline")
|
// id("accept_decline")
|
||||||
positiveText(host.stringProvider.getString(R.string.action_accept).toEpoxyCharSequence())
|
// positiveText(host.stringProvider.getString(R.string.action_accept).toEpoxyCharSequence())
|
||||||
destructiveText(host.stringProvider.getString(R.string.action_decline).toEpoxyCharSequence())
|
// destructiveText(host.stringProvider.getString(R.string.action_decline).toEpoxyCharSequence())
|
||||||
positiveButtonClickAction { host.listener?.acceptRequest() }
|
// positiveButtonClickAction { host.listener?.acceptRequest() }
|
||||||
destructiveButtonClickAction { host.listener?.declineRequest() }
|
// destructiveButtonClickAction { host.listener?.declineRequest() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.isMe && state.canCrossSign) {
|
// if (state.isMe && state.canCrossSign) {
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep_notMe")
|
// id("sep_notMe")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("wasnote")
|
// id("wasnote")
|
||||||
title(host.stringProvider.getString(R.string.verify_new_session_was_not_me))
|
// title(host.stringProvider.getString(R.string.verify_new_session_was_not_me))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
subTitle(host.stringProvider.getString(R.string.verify_new_session_compromized))
|
// subTitle(host.stringProvider.getString(R.string.verify_new_session_compromized))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.onClickOnWasNotMe() }
|
// listener { host.listener?.onClickOnWasNotMe() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
interface Listener {
|
// interface Listener {
|
||||||
fun openCamera()
|
// fun openCamera()
|
||||||
fun doVerifyBySas()
|
// fun doVerifyBySas()
|
||||||
fun onClickOnWasNotMe()
|
// fun onClickOnWasNotMe()
|
||||||
fun acceptRequest()
|
// fun acceptRequest()
|
||||||
fun declineRequest()
|
// fun declineRequest()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,136 +1,136 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.choose
|
// package im.vector.app.features.crypto.verification.choose
|
||||||
|
//
|
||||||
import android.app.Activity
|
// import android.app.Activity
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
// import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.cleanup
|
// import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
// import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
// import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
// import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.app.core.utils.checkPermissions
|
// import im.vector.app.core.utils.checkPermissions
|
||||||
import im.vector.app.core.utils.onPermissionDeniedDialog
|
// import im.vector.app.core.utils.onPermissionDeniedDialog
|
||||||
import im.vector.app.core.utils.registerForPermissionsResult
|
// import im.vector.app.core.utils.registerForPermissionsResult
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationAction
|
// import im.vector.app.features.crypto.verification.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
// import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||||
import timber.log.Timber
|
// import timber.log.Timber
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationChooseMethodFragment :
|
// class VerificationChooseMethodFragment :
|
||||||
VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
// VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
VerificationChooseMethodController.Listener {
|
// VerificationChooseMethodController.Listener {
|
||||||
|
//
|
||||||
@Inject lateinit var controller: VerificationChooseMethodController
|
// @Inject lateinit var controller: VerificationChooseMethodController
|
||||||
private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
|
// private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
|
||||||
|
//
|
||||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
|
//
|
||||||
setupRecyclerView()
|
// setupRecyclerView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroyView() {
|
// override fun onDestroyView() {
|
||||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
// views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
// controller.listener = null
|
||||||
super.onDestroyView()
|
// super.onDestroyView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun setupRecyclerView() {
|
// private fun setupRecyclerView() {
|
||||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
// views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
// controller.listener = this
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
// override fun invalidate() = withState(viewModel) { state ->
|
||||||
controller.update(state)
|
// controller.update(state)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun doVerifyBySas() = withState(sharedViewModel) { state ->
|
// override fun doVerifyBySas() = withState(sharedViewModel) { state ->
|
||||||
sharedViewModel.handle(
|
// sharedViewModel.handle(
|
||||||
VerificationAction.StartSASVerification
|
// VerificationAction.StartSASVerification
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
|
// private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
|
||||||
if (allGranted) {
|
// if (allGranted) {
|
||||||
doOpenQRCodeScanner()
|
// doOpenQRCodeScanner()
|
||||||
} else if (deniedPermanently) {
|
// } else if (deniedPermanently) {
|
||||||
activity?.onPermissionDeniedDialog(R.string.denied_permission_camera)
|
// activity?.onPermissionDeniedDialog(R.string.denied_permission_camera)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun openCamera() {
|
// override fun openCamera() {
|
||||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
|
// if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
|
||||||
doOpenQRCodeScanner()
|
// doOpenQRCodeScanner()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onClickOnWasNotMe() {
|
// override fun onClickOnWasNotMe() {
|
||||||
sharedViewModel.itWasNotMe()
|
// sharedViewModel.itWasNotMe()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun acceptRequest() {
|
// override fun acceptRequest() {
|
||||||
sharedViewModel.handle(VerificationAction.ReadyPendingVerification)
|
// sharedViewModel.handle(VerificationAction.ReadyPendingVerification)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun declineRequest() {
|
// override fun declineRequest() {
|
||||||
sharedViewModel.handle(VerificationAction.CancelPendingVerification)
|
// sharedViewModel.handle(VerificationAction.CancelPendingVerification)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun doOpenQRCodeScanner() {
|
// private fun doOpenQRCodeScanner() {
|
||||||
QrCodeScannerActivity.startForResult(requireActivity(), scanActivityResultLauncher)
|
// QrCodeScannerActivity.startForResult(requireActivity(), scanActivityResultLauncher)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private val scanActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
// private val scanActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
// if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||||
val scannedQrCode = QrCodeScannerActivity.getResultText(activityResult.data)
|
// val scannedQrCode = QrCodeScannerActivity.getResultText(activityResult.data)
|
||||||
val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(activityResult.data)
|
// val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(activityResult.data)
|
||||||
|
//
|
||||||
if (wasQrCode && !scannedQrCode.isNullOrBlank()) {
|
// if (wasQrCode && !scannedQrCode.isNullOrBlank()) {
|
||||||
onRemoteQrCodeScanned(scannedQrCode)
|
// onRemoteQrCodeScanned(scannedQrCode)
|
||||||
} else {
|
// } else {
|
||||||
Timber.w("It was not a QR code, or empty result")
|
// Timber.w("It was not a QR code, or empty result")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun onRemoteQrCodeScanned(remoteQrCode: String) = withState(sharedViewModel) { state ->
|
// private fun onRemoteQrCodeScanned(remoteQrCode: String) = withState(sharedViewModel) { state ->
|
||||||
sharedViewModel.handle(
|
// sharedViewModel.handle(
|
||||||
VerificationAction.RemoteQrCodeScanned(
|
// VerificationAction.RemoteQrCodeScanned(
|
||||||
state.otherUserId,
|
// state.otherUserId,
|
||||||
state.pendingRequest.invoke()?.transactionId ?: "",
|
// state.pendingRequest.invoke()?.transactionId ?: "",
|
||||||
remoteQrCode
|
// remoteQrCode
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,172 +1,172 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.choose
|
// package im.vector.app.features.crypto.verification.choose
|
||||||
|
//
|
||||||
import com.airbnb.mvrx.MavericksState
|
// import com.airbnb.mvrx.MavericksState
|
||||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
// import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
// import com.airbnb.mvrx.ViewModelContext
|
||||||
import dagger.assisted.Assisted
|
// import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
// import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
// import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.EntryPoints
|
// import dagger.hilt.EntryPoints
|
||||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
// import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||||
import im.vector.app.core.di.SingletonEntryPoint
|
// import im.vector.app.core.di.SingletonEntryPoint
|
||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
// import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.EmptyAction
|
// import im.vector.app.core.platform.EmptyAction
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
// import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
// import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||||
import kotlinx.coroutines.flow.launchIn
|
// import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
// import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
// import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
// import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.Session
|
// import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
// import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
// import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
|
// import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
|
//
|
||||||
data class VerificationChooseMethodViewState(
|
// data class VerificationChooseMethodViewState(
|
||||||
val otherUserId: String = "",
|
// val otherUserId: String = "",
|
||||||
val transactionId: String = "",
|
// val transactionId: String = "",
|
||||||
val otherCanShowQrCode: Boolean = false,
|
// val otherCanShowQrCode: Boolean = false,
|
||||||
val otherCanScanQrCode: Boolean = false,
|
// val otherCanScanQrCode: Boolean = false,
|
||||||
val qrCodeText: String? = null,
|
// val qrCodeText: String? = null,
|
||||||
val sasModeAvailable: Boolean = false,
|
// val sasModeAvailable: Boolean = false,
|
||||||
val isMe: Boolean = false,
|
// val isMe: Boolean = false,
|
||||||
val canCrossSign: Boolean = false,
|
// val canCrossSign: Boolean = false,
|
||||||
val isReadySent: Boolean = false
|
// val isReadySent: Boolean = false
|
||||||
) : MavericksState
|
// ) : MavericksState
|
||||||
|
//
|
||||||
class VerificationChooseMethodViewModel @AssistedInject constructor(
|
// class VerificationChooseMethodViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: VerificationChooseMethodViewState,
|
// @Assisted initialState: VerificationChooseMethodViewState,
|
||||||
private val session: Session
|
// private val session: Session
|
||||||
) : VectorViewModel<VerificationChooseMethodViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener {
|
// ) : VectorViewModel<VerificationChooseMethodViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener {
|
||||||
|
//
|
||||||
init {
|
// init {
|
||||||
// session.cryptoService().verificationService().addListener(this)
|
// // session.cryptoService().verificationService().addListener(this)
|
||||||
|
//
|
||||||
session.cryptoService().verificationService()
|
// session.cryptoService().verificationService()
|
||||||
.requestEventFlow()
|
// .requestEventFlow()
|
||||||
.onEach {
|
// .onEach {
|
||||||
when (it) {
|
// when (it) {
|
||||||
// TODO check transaction id
|
// // TODO check transaction id
|
||||||
is VerificationEvent.RequestAdded -> verificationRequestCreated(it.request)
|
// is VerificationEvent.RequestAdded -> verificationRequestCreated(it.request)
|
||||||
is VerificationEvent.RequestUpdated -> verificationRequestUpdated(it.request)
|
// is VerificationEvent.RequestUpdated -> verificationRequestUpdated(it.request)
|
||||||
is VerificationEvent.TransactionAdded -> transactionCreated(it.transaction)
|
// is VerificationEvent.TransactionAdded -> transactionCreated(it.transaction)
|
||||||
is VerificationEvent.TransactionUpdated -> transactionUpdated(it.transaction)
|
// is VerificationEvent.TransactionUpdated -> transactionUpdated(it.transaction)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
.launchIn(viewModelScope)
|
// .launchIn(viewModelScope)
|
||||||
|
//
|
||||||
viewModelScope.launch {
|
// viewModelScope.launch {
|
||||||
|
//
|
||||||
val verificationService = session.cryptoService().verificationService()
|
// val verificationService = session.cryptoService().verificationService()
|
||||||
val pvr = verificationService.getExistingVerificationRequest(initialState.otherUserId, initialState.transactionId)
|
// val pvr = verificationService.getExistingVerificationRequest(initialState.otherUserId, initialState.transactionId)
|
||||||
|
//
|
||||||
// Get the QR code now, because transaction is already created, so transactionCreated() will not be called
|
// // Get the QR code now, because transaction is already created, so transactionCreated() will not be called
|
||||||
val qrCodeVerificationTransaction = verificationService.getExistingTransaction(initialState.otherUserId, initialState.transactionId)
|
// val qrCodeVerificationTransaction = verificationService.getExistingTransaction(initialState.otherUserId, initialState.transactionId)
|
||||||
|
//
|
||||||
setState {
|
|
||||||
VerificationChooseMethodViewState(
|
|
||||||
otherUserId = initialState.otherUserId,
|
|
||||||
isMe = session.myUserId == pvr?.otherUserId,
|
|
||||||
canCrossSign = session.cryptoService().crossSigningService().canCrossSign(),
|
|
||||||
transactionId = pvr?.transactionId ?: initialState.transactionId,
|
|
||||||
otherCanShowQrCode = pvr?.otherCanShowQrCode.orFalse(),
|
|
||||||
otherCanScanQrCode = pvr?.otherCanScanQrCode.orFalse(),
|
|
||||||
qrCodeText = pvr?.qrCodeText,
|
|
||||||
sasModeAvailable = pvr?.isSasSupported.orFalse(),
|
|
||||||
isReadySent = pvr?.state == EVerificationState.Ready
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transactionCreated(tx: VerificationTransaction) {
|
|
||||||
transactionUpdated(tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
|
|
||||||
// if (tx.transactionId == state.transactionId && tx is QrCodeVerificationTransaction) {
|
|
||||||
// setState {
|
// setState {
|
||||||
// copy(
|
// VerificationChooseMethodViewState(
|
||||||
// qrCodeText = tx.qrCodeText
|
// otherUserId = initialState.otherUserId,
|
||||||
|
// isMe = session.myUserId == pvr?.otherUserId,
|
||||||
|
// canCrossSign = session.cryptoService().crossSigningService().canCrossSign(),
|
||||||
|
// transactionId = pvr?.transactionId ?: initialState.transactionId,
|
||||||
|
// otherCanShowQrCode = pvr?.otherCanShowQrCode.orFalse(),
|
||||||
|
// otherCanScanQrCode = pvr?.otherCanScanQrCode.orFalse(),
|
||||||
|
// qrCodeText = pvr?.qrCodeText,
|
||||||
|
// sasModeAvailable = pvr?.isSasSupported.orFalse(),
|
||||||
|
// isReadySent = pvr?.state == EVerificationState.Ready
|
||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
//
|
||||||
|
//
|
||||||
override fun verificationRequestCreated(pr: PendingVerificationRequest) {
|
// }
|
||||||
verificationRequestUpdated(pr)
|
//
|
||||||
}
|
// override fun transactionCreated(tx: VerificationTransaction) {
|
||||||
|
// transactionUpdated(tx)
|
||||||
override fun verificationRequestUpdated(pr: PendingVerificationRequest) = withState { state ->
|
// }
|
||||||
viewModelScope.launch {
|
//
|
||||||
val pvr = session.cryptoService().verificationService().getExistingVerificationRequest(state.otherUserId, state.transactionId)
|
// override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
|
||||||
|
// // if (tx.transactionId == state.transactionId && tx is QrCodeVerificationTransaction) {
|
||||||
setState {
|
// // setState {
|
||||||
copy(
|
// // copy(
|
||||||
otherCanShowQrCode = pvr?.otherCanShowQrCode.orFalse(),
|
// // qrCodeText = tx.qrCodeText
|
||||||
otherCanScanQrCode = pvr?.otherCanScanQrCode.orFalse(),
|
// // )
|
||||||
sasModeAvailable = pvr?.isSasSupported.orFalse(),
|
// // }
|
||||||
isReadySent = pvr?.state == EVerificationState.Ready,
|
// // }
|
||||||
qrCodeText = pvr?.qrCodeText
|
// }
|
||||||
)
|
//
|
||||||
}
|
// override fun verificationRequestCreated(pr: PendingVerificationRequest) {
|
||||||
}
|
// verificationRequestUpdated(pr)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@AssistedFactory
|
// override fun verificationRequestUpdated(pr: PendingVerificationRequest) = withState { state ->
|
||||||
interface Factory : MavericksAssistedViewModelFactory<VerificationChooseMethodViewModel, VerificationChooseMethodViewState> {
|
// viewModelScope.launch {
|
||||||
override fun create(initialState: VerificationChooseMethodViewState): VerificationChooseMethodViewModel
|
// val pvr = session.cryptoService().verificationService().getExistingVerificationRequest(state.otherUserId, state.transactionId)
|
||||||
}
|
//
|
||||||
|
// setState {
|
||||||
companion object : MavericksViewModelFactory<VerificationChooseMethodViewModel, VerificationChooseMethodViewState> by hiltMavericksViewModelFactory() {
|
// copy(
|
||||||
|
// otherCanShowQrCode = pvr?.otherCanShowQrCode.orFalse(),
|
||||||
override fun initialState(viewModelContext: ViewModelContext): VerificationChooseMethodViewState {
|
// otherCanScanQrCode = pvr?.otherCanScanQrCode.orFalse(),
|
||||||
val args: VerificationBottomSheet.VerificationArgs = viewModelContext.args()
|
// sasModeAvailable = pvr?.isSasSupported.orFalse(),
|
||||||
val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
|
// isReadySent = pvr?.state == EVerificationState.Ready,
|
||||||
val verificationService = session.cryptoService().verificationService()
|
// qrCodeText = pvr?.qrCodeText
|
||||||
// val pvr = verificationService.getExistingVerificationRequest(args.otherUserId, args.verificationId)
|
// )
|
||||||
|
// }
|
||||||
// Get the QR code now, because transaction is already created, so transactionCreated() will not be called
|
// }
|
||||||
// val qrCodeVerificationTransaction = verificationService.getExistingTransaction(args.otherUserId, args.verificationId ?: "")
|
// }
|
||||||
|
//
|
||||||
return VerificationChooseMethodViewState(
|
// @AssistedFactory
|
||||||
otherUserId = args.otherUserId,
|
// interface Factory : MavericksAssistedViewModelFactory<VerificationChooseMethodViewModel, VerificationChooseMethodViewState> {
|
||||||
// isMe = session.myUserId == pvr?.otherUserId,
|
// override fun create(initialState: VerificationChooseMethodViewState): VerificationChooseMethodViewModel
|
||||||
canCrossSign = session.cryptoService().crossSigningService().canCrossSign(),
|
// }
|
||||||
transactionId = args.verificationId ?: "",
|
//
|
||||||
// otherCanShowQrCode = pvr?.otherCanShowQrCode().orFalse(),
|
// companion object : MavericksViewModelFactory<VerificationChooseMethodViewModel, VerificationChooseMethodViewState> by hiltMavericksViewModelFactory() {
|
||||||
// otherCanScanQrCode = pvr?.otherCanScanQrCode().orFalse(),
|
//
|
||||||
// qrCodeText = (qrCodeVerificationTransaction as? QrCodeVerificationTransaction)?.qrCodeText,
|
// override fun initialState(viewModelContext: ViewModelContext): VerificationChooseMethodViewState {
|
||||||
// sasModeAvailable = pvr?.isSasSupported().orFalse()
|
// val args: VerificationBottomSheet.VerificationArgs = viewModelContext.args()
|
||||||
)
|
// val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
|
||||||
}
|
// val verificationService = session.cryptoService().verificationService()
|
||||||
}
|
// // val pvr = verificationService.getExistingVerificationRequest(args.otherUserId, args.verificationId)
|
||||||
|
//
|
||||||
override fun onCleared() {
|
// // Get the QR code now, because transaction is already created, so transactionCreated() will not be called
|
||||||
// session.cryptoService().verificationService().removeListener(this)
|
// // val qrCodeVerificationTransaction = verificationService.getExistingTransaction(args.otherUserId, args.verificationId ?: "")
|
||||||
super.onCleared()
|
//
|
||||||
}
|
// return VerificationChooseMethodViewState(
|
||||||
|
// otherUserId = args.otherUserId,
|
||||||
override fun handle(action: EmptyAction) {}
|
// // isMe = session.myUserId == pvr?.otherUserId,
|
||||||
}
|
// canCrossSign = session.cryptoService().crossSigningService().canCrossSign(),
|
||||||
|
// transactionId = args.verificationId ?: "",
|
||||||
|
// // otherCanShowQrCode = pvr?.otherCanShowQrCode().orFalse(),
|
||||||
|
// // otherCanScanQrCode = pvr?.otherCanScanQrCode().orFalse(),
|
||||||
|
// // qrCodeText = (qrCodeVerificationTransaction as? QrCodeVerificationTransaction)?.qrCodeText,
|
||||||
|
// // sasModeAvailable = pvr?.isSasSupported().orFalse()
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onCleared() {
|
||||||
|
// // session.cryptoService().verificationService().removeListener(this)
|
||||||
|
// super.onCleared()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun handle(action: EmptyAction) {}
|
||||||
|
// }
|
||||||
|
@ -1,143 +1,143 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2020 New Vector Ltd
|
// * Copyright 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.conclusion
|
// package im.vector.app.features.crypto.verification.conclusion
|
||||||
|
//
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.html.EventHtmlRenderer
|
// import im.vector.app.features.html.EventHtmlRenderer
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
// import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationConclusionController @Inject constructor(
|
// class VerificationConclusionController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider,
|
// private val colorProvider: ColorProvider,
|
||||||
private val eventHtmlRenderer: EventHtmlRenderer
|
// private val eventHtmlRenderer: EventHtmlRenderer
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var listener: Listener? = null
|
// var listener: Listener? = null
|
||||||
|
//
|
||||||
private var viewState: VerificationConclusionViewState? = null
|
// private var viewState: VerificationConclusionViewState? = null
|
||||||
|
//
|
||||||
fun update(viewState: VerificationConclusionViewState) {
|
// fun update(viewState: VerificationConclusionViewState) {
|
||||||
this.viewState = viewState
|
// this.viewState = viewState
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val state = viewState ?: return
|
// val state = viewState ?: return
|
||||||
val host = this
|
// val host = this
|
||||||
|
//
|
||||||
when (state.conclusionState) {
|
// when (state.conclusionState) {
|
||||||
ConclusionState.SUCCESS -> {
|
// ConclusionState.SUCCESS -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(
|
// notice(
|
||||||
host.stringProvider.getString(
|
// host.stringProvider.getString(
|
||||||
if (state.isSelfVerification) R.string.verification_conclusion_ok_self_notice
|
// if (state.isSelfVerification) R.string.verification_conclusion_ok_self_notice
|
||||||
else R.string.verification_conclusion_ok_notice
|
// else R.string.verification_conclusion_ok_notice
|
||||||
)
|
// )
|
||||||
.toEpoxyCharSequence()
|
// .toEpoxyCharSequence()
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationBigImageItem {
|
// bottomSheetVerificationBigImageItem {
|
||||||
id("image")
|
// id("image")
|
||||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
// roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomDone()
|
// bottomDone()
|
||||||
}
|
// }
|
||||||
ConclusionState.WARNING -> {
|
// ConclusionState.WARNING -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verification_conclusion_not_secure).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verification_conclusion_not_secure).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationBigImageItem {
|
// bottomSheetVerificationBigImageItem {
|
||||||
id("image")
|
// id("image")
|
||||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Warning)
|
// roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Warning)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("warning_notice")
|
// id("warning_notice")
|
||||||
notice(host.eventHtmlRenderer.render(host.stringProvider.getString(R.string.verification_conclusion_compromised)).toEpoxyCharSequence())
|
// notice(host.eventHtmlRenderer.render(host.stringProvider.getString(R.string.verification_conclusion_compromised)).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomGotIt()
|
// bottomGotIt()
|
||||||
}
|
// }
|
||||||
ConclusionState.INVALID_QR_CODE -> {
|
// ConclusionState.INVALID_QR_CODE -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("invalid_qr")
|
// id("invalid_qr")
|
||||||
notice(host.stringProvider.getString(R.string.verify_invalid_qr_notice).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verify_invalid_qr_notice).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomGotIt()
|
// bottomGotIt()
|
||||||
}
|
// }
|
||||||
ConclusionState.CANCELLED -> {
|
// ConclusionState.CANCELLED -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice_cancelled")
|
// id("notice_cancelled")
|
||||||
notice(host.stringProvider.getString(R.string.verify_cancelled_notice).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verify_cancelled_notice).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomGotIt()
|
// bottomGotIt()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun bottomDone() {
|
// private fun bottomDone() {
|
||||||
val host = this
|
// val host = this
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("done")
|
// id("done")
|
||||||
title(host.stringProvider.getString(R.string.done))
|
// title(host.stringProvider.getString(R.string.done))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.onButtonTapped(true) }
|
// listener { host.listener?.onButtonTapped(true) }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun bottomGotIt() {
|
// private fun bottomGotIt() {
|
||||||
val host = this
|
// val host = this
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("got_it")
|
// id("got_it")
|
||||||
title(host.stringProvider.getString(R.string.sas_got_it))
|
// title(host.stringProvider.getString(R.string.sas_got_it))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.onButtonTapped(false) }
|
// listener { host.listener?.onButtonTapped(false) }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
interface Listener {
|
// interface Listener {
|
||||||
fun onButtonTapped(success: Boolean)
|
// fun onButtonTapped(success: Boolean)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,82 +1,82 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.conclusion
|
// package im.vector.app.features.crypto.verification.conclusion
|
||||||
|
//
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.os.Parcelable
|
// import android.os.Parcelable
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
// import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.extensions.cleanup
|
// import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
// import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationAction
|
// import im.vector.app.features.crypto.verification.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import kotlinx.parcelize.Parcelize
|
// import kotlinx.parcelize.Parcelize
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationConclusionFragment :
|
// class VerificationConclusionFragment :
|
||||||
VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
// VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
VerificationConclusionController.Listener {
|
// VerificationConclusionController.Listener {
|
||||||
|
//
|
||||||
@Inject lateinit var controller: VerificationConclusionController
|
// @Inject lateinit var controller: VerificationConclusionController
|
||||||
|
//
|
||||||
@Parcelize
|
// @Parcelize
|
||||||
data class Args(
|
// data class Args(
|
||||||
val isSuccessFull: Boolean,
|
// val isSuccessFull: Boolean,
|
||||||
val cancelReason: String?,
|
// val cancelReason: String?,
|
||||||
val isMe: Boolean
|
// val isMe: Boolean
|
||||||
) : Parcelable
|
// ) : Parcelable
|
||||||
|
//
|
||||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class)
|
// private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
|
//
|
||||||
setupRecyclerView()
|
// setupRecyclerView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroyView() {
|
// override fun onDestroyView() {
|
||||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
// views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
// controller.listener = null
|
||||||
super.onDestroyView()
|
// super.onDestroyView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun setupRecyclerView() {
|
// private fun setupRecyclerView() {
|
||||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
// views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
// controller.listener = this
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
// override fun invalidate() = withState(viewModel) { state ->
|
||||||
controller.update(state)
|
// controller.update(state)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onButtonTapped(success: Boolean) {
|
// override fun onButtonTapped(success: Boolean) {
|
||||||
sharedViewModel.handle(VerificationAction.GotItConclusion(success))
|
// sharedViewModel.handle(VerificationAction.GotItConclusion(success))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,68 +1,68 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.conclusion
|
// package im.vector.app.features.crypto.verification.conclusion
|
||||||
|
//
|
||||||
import com.airbnb.mvrx.MavericksState
|
// import com.airbnb.mvrx.MavericksState
|
||||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
// import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
// import com.airbnb.mvrx.ViewModelContext
|
||||||
import im.vector.app.core.platform.EmptyAction
|
// import im.vector.app.core.platform.EmptyAction
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
// import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
// import im.vector.app.core.platform.VectorViewModel
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
// import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
// import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
||||||
|
//
|
||||||
data class VerificationConclusionViewState(
|
// data class VerificationConclusionViewState(
|
||||||
val conclusionState: ConclusionState = ConclusionState.CANCELLED,
|
// val conclusionState: ConclusionState = ConclusionState.CANCELLED,
|
||||||
val isSelfVerification: Boolean = false
|
// val isSelfVerification: Boolean = false
|
||||||
) : MavericksState
|
// ) : MavericksState
|
||||||
|
//
|
||||||
enum class ConclusionState {
|
// enum class ConclusionState {
|
||||||
SUCCESS,
|
// SUCCESS,
|
||||||
WARNING,
|
// WARNING,
|
||||||
CANCELLED,
|
// CANCELLED,
|
||||||
INVALID_QR_CODE
|
// INVALID_QR_CODE
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
class VerificationConclusionViewModel(initialState: VerificationConclusionViewState) :
|
// class VerificationConclusionViewModel(initialState: VerificationConclusionViewState) :
|
||||||
VectorViewModel<VerificationConclusionViewState, EmptyAction, EmptyViewEvents>(initialState) {
|
// VectorViewModel<VerificationConclusionViewState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||||
|
//
|
||||||
companion object : MavericksViewModelFactory<VerificationConclusionViewModel, VerificationConclusionViewState> {
|
// companion object : MavericksViewModelFactory<VerificationConclusionViewModel, VerificationConclusionViewState> {
|
||||||
|
//
|
||||||
override fun initialState(viewModelContext: ViewModelContext): VerificationConclusionViewState? {
|
// override fun initialState(viewModelContext: ViewModelContext): VerificationConclusionViewState? {
|
||||||
val args = viewModelContext.args<VerificationConclusionFragment.Args>()
|
// val args = viewModelContext.args<VerificationConclusionFragment.Args>()
|
||||||
|
//
|
||||||
return when (safeValueOf(args.cancelReason)) {
|
// return when (safeValueOf(args.cancelReason)) {
|
||||||
CancelCode.QrCodeInvalid -> {
|
// CancelCode.QrCodeInvalid -> {
|
||||||
VerificationConclusionViewState(ConclusionState.INVALID_QR_CODE, args.isMe)
|
// VerificationConclusionViewState(ConclusionState.INVALID_QR_CODE, args.isMe)
|
||||||
}
|
// }
|
||||||
CancelCode.MismatchedUser,
|
// CancelCode.MismatchedUser,
|
||||||
CancelCode.MismatchedSas,
|
// CancelCode.MismatchedSas,
|
||||||
CancelCode.MismatchedCommitment,
|
// CancelCode.MismatchedCommitment,
|
||||||
CancelCode.MismatchedKeys -> {
|
// CancelCode.MismatchedKeys -> {
|
||||||
VerificationConclusionViewState(ConclusionState.WARNING, args.isMe)
|
// VerificationConclusionViewState(ConclusionState.WARNING, args.isMe)
|
||||||
}
|
// }
|
||||||
else -> {
|
// else -> {
|
||||||
VerificationConclusionViewState(
|
// VerificationConclusionViewState(
|
||||||
if (args.isSuccessFull) ConclusionState.SUCCESS else ConclusionState.CANCELLED,
|
// if (args.isSuccessFull) ConclusionState.SUCCESS else ConclusionState.CANCELLED,
|
||||||
args.isMe
|
// args.isMe
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun handle(action: EmptyAction) {}
|
// override fun handle(action: EmptyAction) {}
|
||||||
}
|
// }
|
||||||
|
@ -1,168 +1,168 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2020 New Vector Ltd
|
// * Copyright 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.emoji
|
// package im.vector.app.features.crypto.verification.emoji
|
||||||
|
//
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import com.airbnb.mvrx.Fail
|
// import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Success
|
// import com.airbnb.mvrx.Success
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.epoxy.errorWithRetryItem
|
// import im.vector.app.core.epoxy.errorWithRetryItem
|
||||||
import im.vector.app.core.error.ErrorFormatter
|
// import im.vector.app.core.error.ErrorFormatter
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationDecimalCodeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationDecimalCodeItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationEmojisItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationEmojisItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
||||||
import im.vector.app.features.displayname.getBestName
|
// import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationEmojiCodeController @Inject constructor(
|
// class VerificationEmojiCodeController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider,
|
// private val colorProvider: ColorProvider,
|
||||||
private val errorFormatter: ErrorFormatter
|
// private val errorFormatter: ErrorFormatter
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var listener: Listener? = null
|
// var listener: Listener? = null
|
||||||
|
//
|
||||||
private var viewState: VerificationEmojiCodeViewState? = null
|
// private var viewState: VerificationEmojiCodeViewState? = null
|
||||||
|
//
|
||||||
fun update(viewState: VerificationEmojiCodeViewState) {
|
// fun update(viewState: VerificationEmojiCodeViewState) {
|
||||||
this.viewState = viewState
|
// this.viewState = viewState
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val state = viewState ?: return
|
// val state = viewState ?: return
|
||||||
|
//
|
||||||
if (state.supportsEmoji) {
|
// if (state.supportsEmoji) {
|
||||||
buildEmojiItem(state)
|
// buildEmojiItem(state)
|
||||||
} else {
|
// } else {
|
||||||
buildDecimal(state)
|
// buildDecimal(state)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun buildEmojiItem(state: VerificationEmojiCodeViewState) {
|
// private fun buildEmojiItem(state: VerificationEmojiCodeViewState) {
|
||||||
val host = this
|
// val host = this
|
||||||
when (val emojiDescription = state.emojiDescription) {
|
// when (val emojiDescription = state.emojiDescription) {
|
||||||
is Success -> {
|
// is Success -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verification_emoji_notice).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verification_emoji_notice).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationEmojisItem {
|
// bottomSheetVerificationEmojisItem {
|
||||||
id("emojis")
|
// id("emojis")
|
||||||
emojiRepresentation0(emojiDescription()[0])
|
// emojiRepresentation0(emojiDescription()[0])
|
||||||
emojiRepresentation1(emojiDescription()[1])
|
// emojiRepresentation1(emojiDescription()[1])
|
||||||
emojiRepresentation2(emojiDescription()[2])
|
// emojiRepresentation2(emojiDescription()[2])
|
||||||
emojiRepresentation3(emojiDescription()[3])
|
// emojiRepresentation3(emojiDescription()[3])
|
||||||
emojiRepresentation4(emojiDescription()[4])
|
// emojiRepresentation4(emojiDescription()[4])
|
||||||
emojiRepresentation5(emojiDescription()[5])
|
// emojiRepresentation5(emojiDescription()[5])
|
||||||
emojiRepresentation6(emojiDescription()[6])
|
// emojiRepresentation6(emojiDescription()[6])
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
buildActions(state)
|
// buildActions(state)
|
||||||
}
|
// }
|
||||||
is Fail -> {
|
// is Fail -> {
|
||||||
errorWithRetryItem {
|
// errorWithRetryItem {
|
||||||
id("error")
|
// id("error")
|
||||||
text(host.errorFormatter.toHumanReadable(emojiDescription.error))
|
// text(host.errorFormatter.toHumanReadable(emojiDescription.error))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else -> {
|
// else -> {
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.please_wait))
|
// title(host.stringProvider.getString(R.string.please_wait))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun buildDecimal(state: VerificationEmojiCodeViewState) {
|
// private fun buildDecimal(state: VerificationEmojiCodeViewState) {
|
||||||
val host = this
|
// val host = this
|
||||||
when (val decimalDescription = state.decimalDescription) {
|
// when (val decimalDescription = state.decimalDescription) {
|
||||||
is Success -> {
|
// is Success -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verification_code_notice).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verification_code_notice).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationDecimalCodeItem {
|
// bottomSheetVerificationDecimalCodeItem {
|
||||||
id("decimal")
|
// id("decimal")
|
||||||
code(state.decimalDescription.invoke() ?: "")
|
// code(state.decimalDescription.invoke() ?: "")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
buildActions(state)
|
// buildActions(state)
|
||||||
}
|
// }
|
||||||
is Fail -> {
|
// is Fail -> {
|
||||||
errorWithRetryItem {
|
// errorWithRetryItem {
|
||||||
id("error")
|
// id("error")
|
||||||
text(host.errorFormatter.toHumanReadable(decimalDescription.error))
|
// text(host.errorFormatter.toHumanReadable(decimalDescription.error))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else -> {
|
// else -> {
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.please_wait))
|
// title(host.stringProvider.getString(R.string.please_wait))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun buildActions(state: VerificationEmojiCodeViewState) {
|
// private fun buildActions(state: VerificationEmojiCodeViewState) {
|
||||||
val host = this
|
// val host = this
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.isWaitingFromOther) {
|
// if (state.isWaitingFromOther) {
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUser.getBestName()))
|
// title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUser.getBestName()))
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("ko")
|
// id("ko")
|
||||||
title(host.stringProvider.getString(R.string.verification_sas_do_not_match))
|
// title(host.stringProvider.getString(R.string.verification_sas_do_not_match))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
iconRes(R.drawable.ic_check_off)
|
// iconRes(R.drawable.ic_check_off)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
listener { host.listener?.onDoNotMatchButtonTapped() }
|
// listener { host.listener?.onDoNotMatchButtonTapped() }
|
||||||
}
|
// }
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep1")
|
// id("sep1")
|
||||||
}
|
// }
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("ok")
|
// id("ok")
|
||||||
title(host.stringProvider.getString(R.string.verification_sas_match))
|
// title(host.stringProvider.getString(R.string.verification_sas_match))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
iconRes(R.drawable.ic_check_on)
|
// iconRes(R.drawable.ic_check_on)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
listener { host.listener?.onMatchButtonTapped() }
|
// listener { host.listener?.onMatchButtonTapped() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
interface Listener {
|
// interface Listener {
|
||||||
fun onDoNotMatchButtonTapped()
|
// fun onDoNotMatchButtonTapped()
|
||||||
fun onMatchButtonTapped()
|
// fun onMatchButtonTapped()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,81 +1,81 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.emoji
|
// package im.vector.app.features.crypto.verification.emoji
|
||||||
|
//
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
// import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.extensions.cleanup
|
// import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
// import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationAction
|
// import im.vector.app.features.crypto.verification.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationEmojiCodeFragment :
|
// class VerificationEmojiCodeFragment :
|
||||||
VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
// VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
VerificationEmojiCodeController.Listener {
|
// VerificationEmojiCodeController.Listener {
|
||||||
|
//
|
||||||
@Inject lateinit var controller: VerificationEmojiCodeController
|
// @Inject lateinit var controller: VerificationEmojiCodeController
|
||||||
|
//
|
||||||
private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
|
// private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
|
||||||
|
//
|
||||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
|
//
|
||||||
setupRecyclerView()
|
// setupRecyclerView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroyView() {
|
// override fun onDestroyView() {
|
||||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
// views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
// controller.listener = null
|
||||||
super.onDestroyView()
|
// super.onDestroyView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun setupRecyclerView() {
|
// private fun setupRecyclerView() {
|
||||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
// views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
// controller.listener = this
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
// override fun invalidate() = withState(viewModel) { state ->
|
||||||
controller.update(state)
|
// controller.update(state)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onMatchButtonTapped() = withState(viewModel) { state ->
|
// override fun onMatchButtonTapped() = withState(viewModel) { state ->
|
||||||
val otherUserId = state.otherUser.id
|
// val otherUserId = state.otherUser.id
|
||||||
val txId = state.transactionId ?: return@withState
|
// val txId = state.transactionId ?: return@withState
|
||||||
sharedViewModel.handle(VerificationAction.SASMatchAction)
|
// sharedViewModel.handle(VerificationAction.SASMatchAction)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDoNotMatchButtonTapped() = withState(viewModel) { state ->
|
// override fun onDoNotMatchButtonTapped() = withState(viewModel) { state ->
|
||||||
val otherUserId = state.otherUser.id
|
// val otherUserId = state.otherUser.id
|
||||||
val txId = state.transactionId ?: return@withState
|
// val txId = state.transactionId ?: return@withState
|
||||||
sharedViewModel.handle(VerificationAction.SASDoNotMatchAction)
|
// sharedViewModel.handle(VerificationAction.SASDoNotMatchAction)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,209 +1,209 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.emoji
|
// package im.vector.app.features.crypto.verification.emoji
|
||||||
|
//
|
||||||
import com.airbnb.mvrx.Async
|
// import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.Fail
|
// import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Loading
|
// import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.MavericksState
|
// import com.airbnb.mvrx.MavericksState
|
||||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
// import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.Success
|
// import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.Uninitialized
|
// import com.airbnb.mvrx.Uninitialized
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
// import com.airbnb.mvrx.ViewModelContext
|
||||||
import dagger.assisted.Assisted
|
// import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
// import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
// import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.EntryPoints
|
// import dagger.hilt.EntryPoints
|
||||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
// import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||||
import im.vector.app.core.di.SingletonEntryPoint
|
// import im.vector.app.core.di.SingletonEntryPoint
|
||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
// import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.EmptyAction
|
// import im.vector.app.core.platform.EmptyAction
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
// import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
// import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||||
import kotlinx.coroutines.flow.launchIn
|
// import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
// import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
// import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.session.Session
|
// import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
// import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
// import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
||||||
import org.matrix.android.sdk.api.session.getUserOrDefault
|
// import org.matrix.android.sdk.api.session.getUserOrDefault
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
// import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
// import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
//
|
||||||
data class VerificationEmojiCodeViewState(
|
// data class VerificationEmojiCodeViewState(
|
||||||
val transactionId: String?,
|
// val transactionId: String?,
|
||||||
val otherUser: MatrixItem,
|
// val otherUser: MatrixItem,
|
||||||
val supportsEmoji: Boolean = true,
|
// val supportsEmoji: Boolean = true,
|
||||||
val emojiDescription: Async<List<EmojiRepresentation>> = Uninitialized,
|
// val emojiDescription: Async<List<EmojiRepresentation>> = Uninitialized,
|
||||||
val decimalDescription: Async<String> = Uninitialized,
|
// val decimalDescription: Async<String> = Uninitialized,
|
||||||
val isWaitingFromOther: Boolean = false
|
// val isWaitingFromOther: Boolean = false
|
||||||
) : MavericksState
|
// ) : MavericksState
|
||||||
|
//
|
||||||
class VerificationEmojiCodeViewModel @AssistedInject constructor(
|
// class VerificationEmojiCodeViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: VerificationEmojiCodeViewState,
|
// @Assisted initialState: VerificationEmojiCodeViewState,
|
||||||
private val session: Session
|
// private val session: Session
|
||||||
) : VectorViewModel<VerificationEmojiCodeViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener {
|
// ) : VectorViewModel<VerificationEmojiCodeViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener {
|
||||||
|
//
|
||||||
init {
|
// init {
|
||||||
|
//
|
||||||
session.cryptoService().verificationService()
|
// session.cryptoService().verificationService()
|
||||||
.requestEventFlow()
|
// .requestEventFlow()
|
||||||
.onEach {
|
// .onEach {
|
||||||
when (it) {
|
// when (it) {
|
||||||
is VerificationEvent.RequestAdded -> verificationRequestCreated(it.request)
|
// is VerificationEvent.RequestAdded -> verificationRequestCreated(it.request)
|
||||||
is VerificationEvent.RequestUpdated -> verificationRequestUpdated(it.request)
|
// is VerificationEvent.RequestUpdated -> verificationRequestUpdated(it.request)
|
||||||
is VerificationEvent.TransactionAdded -> transactionCreated(it.transaction)
|
// is VerificationEvent.TransactionAdded -> transactionCreated(it.transaction)
|
||||||
is VerificationEvent.TransactionUpdated -> transactionUpdated(it.transaction)
|
// is VerificationEvent.TransactionUpdated -> transactionUpdated(it.transaction)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
.launchIn(viewModelScope)
|
// .launchIn(viewModelScope)
|
||||||
|
//
|
||||||
viewModelScope.launch {
|
// viewModelScope.launch {
|
||||||
refreshStateFromTx(
|
// refreshStateFromTx(
|
||||||
session.cryptoService().verificationService()
|
// session.cryptoService().verificationService()
|
||||||
.getExistingTransaction(
|
// .getExistingTransaction(
|
||||||
otherUserId = initialState.otherUser.id,
|
// otherUserId = initialState.otherUser.id,
|
||||||
tid = initialState.transactionId ?: ""
|
// tid = initialState.transactionId ?: ""
|
||||||
) as? SasVerificationTransaction
|
// ) as? SasVerificationTransaction
|
||||||
)
|
// )
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// session.cryptoService().verificationService().addListener(this)
|
// // session.cryptoService().verificationService().addListener(this)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// override fun onCleared() {
|
// // override fun onCleared() {
|
||||||
// session.cryptoService().verificationService().removeListener(this)
|
// // session.cryptoService().verificationService().removeListener(this)
|
||||||
// super.onCleared()
|
// // super.onCleared()
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// private fun refreshStateFromTx(sasTx: SasVerificationTransaction?) {
|
||||||
|
// when (val state = sasTx?.state) {
|
||||||
|
// is VerificationTxState.None,
|
||||||
|
// is VerificationTxState.SasStarted,
|
||||||
|
// is VerificationTxState.SasAccepted,
|
||||||
|
// is VerificationTxState.SasKeySent -> {
|
||||||
|
// setState {
|
||||||
|
// copy(
|
||||||
|
// isWaitingFromOther = false,
|
||||||
|
// supportsEmoji = sasTx.supportsEmoji(),
|
||||||
|
// emojiDescription = Loading<List<EmojiRepresentation>>()
|
||||||
|
// .takeIf { sasTx.supportsEmoji() }
|
||||||
|
// ?: Uninitialized,
|
||||||
|
// decimalDescription = Loading<String>()
|
||||||
|
// .takeIf { sasTx.supportsEmoji().not() }
|
||||||
|
// ?: Uninitialized
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// is VerificationTxState.SasShortCodeReady -> {
|
||||||
|
// setState {
|
||||||
|
// copy(
|
||||||
|
// isWaitingFromOther = false,
|
||||||
|
// supportsEmoji = sasTx.supportsEmoji(),
|
||||||
|
// emojiDescription = if (sasTx.supportsEmoji()) Success(sasTx.getEmojiCodeRepresentation())
|
||||||
|
// else Uninitialized,
|
||||||
|
// decimalDescription = if (!sasTx.supportsEmoji()) Success(sasTx.getDecimalCodeRepresentation().orEmpty())
|
||||||
|
// else Uninitialized
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// is VerificationTxState.SasMacReceived -> {
|
||||||
|
// if (state.codeConfirmed) {
|
||||||
|
// setState {
|
||||||
|
// copy(isWaitingFromOther = true)
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// setState {
|
||||||
|
// copy(
|
||||||
|
// isWaitingFromOther = false,
|
||||||
|
// supportsEmoji = sasTx.supportsEmoji(),
|
||||||
|
// emojiDescription = if (sasTx.supportsEmoji()) Success(sasTx.getEmojiCodeRepresentation())
|
||||||
|
// else Uninitialized,
|
||||||
|
// decimalDescription = if (!sasTx.supportsEmoji()) Success(sasTx.getDecimalCodeRepresentation().orEmpty())
|
||||||
|
// else Uninitialized
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// is VerificationTxState.SasMacSent,
|
||||||
|
// is VerificationTxState.Verified -> {
|
||||||
|
// setState {
|
||||||
|
// copy(isWaitingFromOther = true)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// is VerificationTxState.Cancelled -> {
|
||||||
|
// // The fragment should not be rendered in this state,
|
||||||
|
// // it should have been replaced by a conclusion fragment
|
||||||
|
// setState {
|
||||||
|
// copy(
|
||||||
|
// isWaitingFromOther = false,
|
||||||
|
// supportsEmoji = sasTx.supportsEmoji(),
|
||||||
|
// emojiDescription = Fail(Throwable("Transaction Cancelled")),
|
||||||
|
// decimalDescription = Fail(Throwable("Transaction Cancelled"))
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// null -> {
|
||||||
|
// setState {
|
||||||
|
// copy(
|
||||||
|
// isWaitingFromOther = false,
|
||||||
|
// emojiDescription = Fail(Throwable("Unknown Transaction")),
|
||||||
|
// decimalDescription = Fail(Throwable("Unknown Transaction"))
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else -> Unit
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun transactionCreated(tx: VerificationTransaction) {
|
||||||
|
// transactionUpdated(tx)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
|
||||||
|
// if (tx.transactionId == state.transactionId && tx is SasVerificationTransaction) {
|
||||||
|
// refreshStateFromTx(tx)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @AssistedFactory
|
||||||
|
// interface Factory : MavericksAssistedViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> {
|
||||||
|
// override fun create(initialState: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// companion object : MavericksViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> by hiltMavericksViewModelFactory() {
|
||||||
|
//
|
||||||
|
// override fun initialState(viewModelContext: ViewModelContext): VerificationEmojiCodeViewState {
|
||||||
|
// val args = viewModelContext.args<VerificationBottomSheet.VerificationArgs>()
|
||||||
|
// val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
|
||||||
|
// val matrixItem = session.getUserOrDefault(args.otherUserId).toMatrixItem()
|
||||||
|
//
|
||||||
|
// return VerificationEmojiCodeViewState(
|
||||||
|
// transactionId = args.verificationId,
|
||||||
|
// otherUser = matrixItem
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun handle(action: EmptyAction) {
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private fun refreshStateFromTx(sasTx: SasVerificationTransaction?) {
|
|
||||||
when (val state = sasTx?.state) {
|
|
||||||
is VerificationTxState.None,
|
|
||||||
is VerificationTxState.SasStarted,
|
|
||||||
is VerificationTxState.SasAccepted,
|
|
||||||
is VerificationTxState.SasKeySent -> {
|
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
isWaitingFromOther = false,
|
|
||||||
supportsEmoji = sasTx.supportsEmoji(),
|
|
||||||
emojiDescription = Loading<List<EmojiRepresentation>>()
|
|
||||||
.takeIf { sasTx.supportsEmoji() }
|
|
||||||
?: Uninitialized,
|
|
||||||
decimalDescription = Loading<String>()
|
|
||||||
.takeIf { sasTx.supportsEmoji().not() }
|
|
||||||
?: Uninitialized
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is VerificationTxState.SasShortCodeReady -> {
|
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
isWaitingFromOther = false,
|
|
||||||
supportsEmoji = sasTx.supportsEmoji(),
|
|
||||||
emojiDescription = if (sasTx.supportsEmoji()) Success(sasTx.getEmojiCodeRepresentation())
|
|
||||||
else Uninitialized,
|
|
||||||
decimalDescription = if (!sasTx.supportsEmoji()) Success(sasTx.getDecimalCodeRepresentation().orEmpty())
|
|
||||||
else Uninitialized
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is VerificationTxState.SasMacReceived -> {
|
|
||||||
if (state.codeConfirmed) {
|
|
||||||
setState {
|
|
||||||
copy(isWaitingFromOther = true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
isWaitingFromOther = false,
|
|
||||||
supportsEmoji = sasTx.supportsEmoji(),
|
|
||||||
emojiDescription = if (sasTx.supportsEmoji()) Success(sasTx.getEmojiCodeRepresentation())
|
|
||||||
else Uninitialized,
|
|
||||||
decimalDescription = if (!sasTx.supportsEmoji()) Success(sasTx.getDecimalCodeRepresentation().orEmpty())
|
|
||||||
else Uninitialized
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is VerificationTxState.SasMacSent,
|
|
||||||
is VerificationTxState.Verified -> {
|
|
||||||
setState {
|
|
||||||
copy(isWaitingFromOther = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is VerificationTxState.Cancelled -> {
|
|
||||||
// The fragment should not be rendered in this state,
|
|
||||||
// it should have been replaced by a conclusion fragment
|
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
isWaitingFromOther = false,
|
|
||||||
supportsEmoji = sasTx.supportsEmoji(),
|
|
||||||
emojiDescription = Fail(Throwable("Transaction Cancelled")),
|
|
||||||
decimalDescription = Fail(Throwable("Transaction Cancelled"))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
null -> {
|
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
isWaitingFromOther = false,
|
|
||||||
emojiDescription = Fail(Throwable("Unknown Transaction")),
|
|
||||||
decimalDescription = Fail(Throwable("Unknown Transaction"))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> Unit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transactionCreated(tx: VerificationTransaction) {
|
|
||||||
transactionUpdated(tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
|
|
||||||
if (tx.transactionId == state.transactionId && tx is SasVerificationTransaction) {
|
|
||||||
refreshStateFromTx(tx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AssistedFactory
|
|
||||||
interface Factory : MavericksAssistedViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> {
|
|
||||||
override fun create(initialState: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : MavericksViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> by hiltMavericksViewModelFactory() {
|
|
||||||
|
|
||||||
override fun initialState(viewModelContext: ViewModelContext): VerificationEmojiCodeViewState {
|
|
||||||
val args = viewModelContext.args<VerificationBottomSheet.VerificationArgs>()
|
|
||||||
val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
|
|
||||||
val matrixItem = session.getUserOrDefault(args.otherUserId).toMatrixItem()
|
|
||||||
|
|
||||||
return VerificationEmojiCodeViewState(
|
|
||||||
transactionId = args.verificationId,
|
|
||||||
otherUser = matrixItem
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handle(action: EmptyAction) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,99 +1,99 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2020 New Vector Ltd
|
// * Copyright 2020 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.qrconfirmation
|
// package im.vector.app.features.crypto.verification.qrconfirmation
|
||||||
|
//
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.displayname.getBestName
|
// import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
// import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationQrScannedByOtherController @Inject constructor(
|
// class VerificationQrScannedByOtherController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider
|
// private val colorProvider: ColorProvider
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var listener: Listener? = null
|
// var listener: Listener? = null
|
||||||
|
//
|
||||||
private var viewState: VerificationBottomSheetViewState? = null
|
// private var viewState: VerificationBottomSheetViewState? = null
|
||||||
|
//
|
||||||
fun update(viewState: VerificationBottomSheetViewState) {
|
// fun update(viewState: VerificationBottomSheetViewState) {
|
||||||
this.viewState = viewState
|
// this.viewState = viewState
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val state = viewState ?: return
|
// val state = viewState ?: return
|
||||||
val host = this
|
// val host = this
|
||||||
|
//
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
apply {
|
// apply {
|
||||||
if (state.isMe) {
|
// if (state.isMe) {
|
||||||
notice(host.stringProvider.getString(R.string.qr_code_scanned_self_verif_notice).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.qr_code_scanned_self_verif_notice).toEpoxyCharSequence())
|
||||||
} else {
|
// } else {
|
||||||
val name = state.otherUserMxItem.getBestName()
|
// val name = state.otherUserMxItem.getBestName()
|
||||||
notice(host.stringProvider.getString(R.string.qr_code_scanned_by_other_notice, name).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.qr_code_scanned_by_other_notice, name).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationBigImageItem {
|
// bottomSheetVerificationBigImageItem {
|
||||||
id("image")
|
// id("image")
|
||||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
// roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("deny")
|
// id("deny")
|
||||||
title(host.stringProvider.getString(R.string.qr_code_scanned_by_other_no))
|
// title(host.stringProvider.getString(R.string.qr_code_scanned_by_other_no))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
iconRes(R.drawable.ic_check_off)
|
// iconRes(R.drawable.ic_check_off)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
listener { host.listener?.onUserDeniesQrCodeScanned() }
|
// listener { host.listener?.onUserDeniesQrCodeScanned() }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep1")
|
// id("sep1")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("confirm")
|
// id("confirm")
|
||||||
title(host.stringProvider.getString(R.string.qr_code_scanned_by_other_yes))
|
// title(host.stringProvider.getString(R.string.qr_code_scanned_by_other_yes))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
iconRes(R.drawable.ic_check_on)
|
// iconRes(R.drawable.ic_check_on)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
listener { host.listener?.onUserConfirmsQrCodeScanned() }
|
// listener { host.listener?.onUserConfirmsQrCodeScanned() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
interface Listener {
|
// interface Listener {
|
||||||
fun onUserConfirmsQrCodeScanned()
|
// fun onUserConfirmsQrCodeScanned()
|
||||||
fun onUserDeniesQrCodeScanned()
|
// fun onUserDeniesQrCodeScanned()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,73 +1,73 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.qrconfirmation
|
// package im.vector.app.features.crypto.verification.qrconfirmation
|
||||||
|
//
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.extensions.cleanup
|
// import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
// import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationAction
|
// import im.vector.app.features.crypto.verification.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationQrScannedByOtherFragment :
|
// class VerificationQrScannedByOtherFragment :
|
||||||
VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
// VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
VerificationQrScannedByOtherController.Listener {
|
// VerificationQrScannedByOtherController.Listener {
|
||||||
|
//
|
||||||
@Inject lateinit var controller: VerificationQrScannedByOtherController
|
// @Inject lateinit var controller: VerificationQrScannedByOtherController
|
||||||
|
//
|
||||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
setupRecyclerView()
|
// setupRecyclerView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
// override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
controller.update(state)
|
// controller.update(state)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroyView() {
|
// override fun onDestroyView() {
|
||||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
// views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
// controller.listener = null
|
||||||
super.onDestroyView()
|
// super.onDestroyView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun setupRecyclerView() {
|
// private fun setupRecyclerView() {
|
||||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
// views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
// controller.listener = this
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onUserConfirmsQrCodeScanned() {
|
// override fun onUserConfirmsQrCodeScanned() {
|
||||||
sharedViewModel.handle(VerificationAction.OtherUserScannedSuccessfully)
|
// sharedViewModel.handle(VerificationAction.OtherUserScannedSuccessfully)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onUserDeniesQrCodeScanned() {
|
// override fun onUserDeniesQrCodeScanned() {
|
||||||
sharedViewModel.handle(VerificationAction.OtherUserDidNotScanned)
|
// sharedViewModel.handle(VerificationAction.OtherUserDidNotScanned)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,185 +1,185 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.request
|
// package im.vector.app.features.crypto.verification.request
|
||||||
|
//
|
||||||
import androidx.core.text.toSpannable
|
// import androidx.core.text.toSpannable
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import com.airbnb.mvrx.Fail
|
// import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Loading
|
// import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.Success
|
// import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.Uninitialized
|
// import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
// import im.vector.app.core.utils.colorizeMatchingText
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewState
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetSelfWaitItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetSelfWaitItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
||||||
import im.vector.app.features.displayname.getBestName
|
// import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
// import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationRequestController @Inject constructor(
|
// class VerificationRequestController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider
|
// private val colorProvider: ColorProvider
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var listener: Listener? = null
|
// var listener: Listener? = null
|
||||||
|
//
|
||||||
private var viewState: VerificationBottomSheetViewState? = null
|
// private var viewState: VerificationBottomSheetViewState? = null
|
||||||
|
//
|
||||||
fun update(viewState: VerificationBottomSheetViewState) {
|
// fun update(viewState: VerificationBottomSheetViewState) {
|
||||||
this.viewState = viewState
|
// this.viewState = viewState
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val state = viewState ?: return
|
// val state = viewState ?: return
|
||||||
val host = this
|
// val host = this
|
||||||
|
//
|
||||||
if (state.selfVerificationMode) {
|
// if (state.selfVerificationMode) {
|
||||||
if (state.hasAnyOtherSession) {
|
// if (state.hasAnyOtherSession) {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verification_open_other_to_verify).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verification_open_other_to_verify).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetSelfWaitItem {
|
// bottomSheetSelfWaitItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep")
|
// id("sep")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.quadSContainsSecrets) {
|
// if (state.quadSContainsSecrets) {
|
||||||
val subtitle = if (state.hasAnyOtherSession) {
|
// val subtitle = if (state.hasAnyOtherSession) {
|
||||||
stringProvider.getString(R.string.verification_use_passphrase)
|
// stringProvider.getString(R.string.verification_use_passphrase)
|
||||||
} else {
|
// } else {
|
||||||
null
|
// null
|
||||||
}
|
// }
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("passphrase")
|
// id("passphrase")
|
||||||
title(host.stringProvider.getString(R.string.verification_cannot_access_other_session))
|
// title(host.stringProvider.getString(R.string.verification_cannot_access_other_session))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
subTitle(subtitle)
|
// subTitle(subtitle)
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.onClickRecoverFromPassphrase() }
|
// listener { host.listener?.onClickRecoverFromPassphrase() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (!state.isVerificationRequired) {
|
// if (!state.isVerificationRequired) {
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep1")
|
// id("sep1")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("skip")
|
// id("skip")
|
||||||
title(host.stringProvider.getString(R.string.action_skip))
|
// title(host.stringProvider.getString(R.string.action_skip))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
listener { host.listener?.onClickSkip() }
|
// listener { host.listener?.onClickSkip() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
val styledText =
|
// val styledText =
|
||||||
if (state.isMe) {
|
// if (state.isMe) {
|
||||||
stringProvider.getString(R.string.verify_new_session_notice)
|
// stringProvider.getString(R.string.verify_new_session_notice)
|
||||||
} else {
|
// } else {
|
||||||
stringProvider.getString(R.string.verification_request_notice, state.otherUserId)
|
// stringProvider.getString(R.string.verification_request_notice, state.otherUserId)
|
||||||
.toSpannable()
|
// .toSpannable()
|
||||||
.colorizeMatchingText(state.otherUserId, colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
|
// .colorizeMatchingText(state.otherUserId, colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(styledText.toEpoxyCharSequence())
|
// notice(styledText.toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep")
|
// id("sep")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
when (val pr = state.pendingRequest) {
|
// when (val pr = state.pendingRequest) {
|
||||||
is Uninitialized -> {
|
// is Uninitialized -> {
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("start")
|
// id("start")
|
||||||
title(host.stringProvider.getString(R.string.start_verification))
|
// title(host.stringProvider.getString(R.string.start_verification))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
subTitle(host.stringProvider.getString(R.string.verification_request_start_notice))
|
// subTitle(host.stringProvider.getString(R.string.verification_request_start_notice))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.onClickOnVerificationStart() }
|
// listener { host.listener?.onClickOnVerificationStart() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
is Loading -> {
|
// is Loading -> {
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUserMxItem.getBestName()))
|
// title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUserMxItem.getBestName()))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
is Success -> {
|
// is Success -> {
|
||||||
if (pr.invoke().state != EVerificationState.Ready) {
|
// if (pr.invoke().state != EVerificationState.Ready) {
|
||||||
if (state.isMe) {
|
// if (state.isMe) {
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.verification_request_waiting))
|
// title(host.stringProvider.getString(R.string.verification_request_waiting))
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUserMxItem.getBestName()))
|
// title(host.stringProvider.getString(R.string.verification_request_waiting_for, state.otherUserMxItem.getBestName()))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
is Fail -> Unit
|
// is Fail -> Unit
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (state.isMe && state.currentDeviceCanCrossSign && !state.selfVerificationMode) {
|
// if (state.isMe && state.currentDeviceCanCrossSign && !state.selfVerificationMode) {
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep_notMe")
|
// id("sep_notMe")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("wasnote")
|
// id("wasnote")
|
||||||
title(host.stringProvider.getString(R.string.verify_new_session_was_not_me))
|
// title(host.stringProvider.getString(R.string.verify_new_session_was_not_me))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
subTitle(host.stringProvider.getString(R.string.verify_new_session_compromized))
|
// subTitle(host.stringProvider.getString(R.string.verify_new_session_compromized))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
// iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.vctr_content_primary))
|
||||||
listener { host.listener?.onClickOnWasNotMe() }
|
// listener { host.listener?.onClickOnWasNotMe() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
interface Listener {
|
// interface Listener {
|
||||||
fun onClickOnVerificationStart()
|
// fun onClickOnVerificationStart()
|
||||||
fun onClickOnWasNotMe()
|
// fun onClickOnWasNotMe()
|
||||||
fun onClickRecoverFromPassphrase()
|
// fun onClickRecoverFromPassphrase()
|
||||||
fun onClickDismiss()
|
// fun onClickDismiss()
|
||||||
fun onClickSkip()
|
// fun onClickSkip()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,85 +1,85 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright 2019 New Vector Ltd
|
// * Copyright 2019 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
package im.vector.app.features.crypto.verification.request
|
// package im.vector.app.features.crypto.verification.request
|
||||||
|
//
|
||||||
import android.os.Bundle
|
// import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.View
|
// import android.view.View
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
// import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.extensions.cleanup
|
// import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
// import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationAction
|
// import im.vector.app.features.crypto.verification.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
// import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationRequestFragment :
|
// class VerificationRequestFragment :
|
||||||
VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
// VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
VerificationRequestController.Listener {
|
// VerificationRequestController.Listener {
|
||||||
|
//
|
||||||
@Inject lateinit var controller: VerificationRequestController
|
// @Inject lateinit var controller: VerificationRequestController
|
||||||
|
//
|
||||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
// private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
// super.onViewCreated(view, savedInstanceState)
|
||||||
setupRecyclerView()
|
// setupRecyclerView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onDestroyView() {
|
// override fun onDestroyView() {
|
||||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
// views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
// controller.listener = null
|
||||||
super.onDestroyView()
|
// super.onDestroyView()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun setupRecyclerView() {
|
// private fun setupRecyclerView() {
|
||||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
// views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
// controller.listener = this
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
// override fun invalidate() = withState(viewModel) { state ->
|
||||||
controller.update(state)
|
// controller.update(state)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onClickOnVerificationStart(): Unit = withState(viewModel) { state ->
|
// override fun onClickOnVerificationStart(): Unit = withState(viewModel) { state ->
|
||||||
viewModel.handle(VerificationAction.RequestVerificationByDM)
|
// viewModel.handle(VerificationAction.RequestVerificationByDM)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onClickRecoverFromPassphrase() {
|
// override fun onClickRecoverFromPassphrase() {
|
||||||
viewModel.handle(VerificationAction.VerifyFromPassphrase)
|
// viewModel.handle(VerificationAction.VerifyFromPassphrase)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onClickDismiss() {
|
// override fun onClickDismiss() {
|
||||||
viewModel.handle(VerificationAction.SkipVerification)
|
// viewModel.handle(VerificationAction.SkipVerification)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onClickSkip() {
|
// override fun onClickSkip() {
|
||||||
viewModel.queryCancel()
|
// viewModel.queryCancel()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun onClickOnWasNotMe() {
|
// override fun onClickOnWasNotMe() {
|
||||||
viewModel.itWasNotMe()
|
// viewModel.itWasNotMe()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,178 +1,178 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
// * Copyright (c) 2022 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.transaction
|
// package im.vector.app.features.crypto.verification.transaction
|
||||||
|
//
|
||||||
import com.airbnb.epoxy.EpoxyController
|
// import com.airbnb.epoxy.EpoxyController
|
||||||
import com.airbnb.mvrx.Async
|
// import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.Fail
|
// import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Loading
|
// import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.Success
|
// import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.Uninitialized
|
// import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.R
|
// import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
// import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||||
import im.vector.app.core.resources.ColorProvider
|
// import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
// import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationEmojisItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationEmojisItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
// import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
||||||
import im.vector.app.features.html.EventHtmlRenderer
|
// import im.vector.app.features.html.EventHtmlRenderer
|
||||||
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
// import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
// import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
// import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
// import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
// import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
// import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
||||||
import javax.inject.Inject
|
// import javax.inject.Inject
|
||||||
|
//
|
||||||
class VerificationTransactionController @Inject constructor(
|
// class VerificationTransactionController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
// private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider,
|
// private val colorProvider: ColorProvider,
|
||||||
private val eventHtmlRenderer: EventHtmlRenderer,
|
// private val eventHtmlRenderer: EventHtmlRenderer,
|
||||||
) : EpoxyController() {
|
// ) : EpoxyController() {
|
||||||
|
//
|
||||||
var aTransaction: Async<VerificationTransaction>? = null
|
// var aTransaction: Async<VerificationTransaction>? = null
|
||||||
|
//
|
||||||
fun update(asyncTransaction: Async<VerificationTransaction>) {
|
// fun update(asyncTransaction: Async<VerificationTransaction>) {
|
||||||
this.aTransaction = asyncTransaction
|
// this.aTransaction = asyncTransaction
|
||||||
requestModelBuild()
|
// requestModelBuild()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun buildModels() {
|
// override fun buildModels() {
|
||||||
val host = this
|
// val host = this
|
||||||
when (aTransaction) {
|
// when (aTransaction) {
|
||||||
null,
|
// null,
|
||||||
Uninitialized -> {
|
// Uninitialized -> {
|
||||||
// empty
|
// // empty
|
||||||
}
|
// }
|
||||||
is Fail -> {
|
// is Fail -> {
|
||||||
}
|
// }
|
||||||
is Loading -> {
|
// is Loading -> {
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.please_wait))
|
// title(host.stringProvider.getString(R.string.please_wait))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
is Success -> {
|
// is Success -> {
|
||||||
val tx = aTransaction?.invoke() ?: return
|
// val tx = aTransaction?.invoke() ?: return
|
||||||
if (tx is SasVerificationTransaction) {
|
// if (tx is SasVerificationTransaction) {
|
||||||
when (val txState = tx.state) {
|
// when (val txState = tx.state) {
|
||||||
VerificationTxState.SasShortCodeReady -> {
|
// VerificationTxState.SasShortCodeReady -> {
|
||||||
buildEmojiItem(tx.getEmojiCodeRepresentation())
|
// buildEmojiItem(tx.getEmojiCodeRepresentation())
|
||||||
}
|
// }
|
||||||
is VerificationTxState.Cancelled -> {
|
// is VerificationTxState.Cancelled -> {
|
||||||
renderCancel(txState.cancelCode)
|
// renderCancel(txState.cancelCode)
|
||||||
}
|
// }
|
||||||
is VerificationTxState.Done -> {
|
// is VerificationTxState.Done -> {
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
else -> {
|
// else -> {
|
||||||
// waiting
|
// // waiting
|
||||||
bottomSheetVerificationWaitingItem {
|
// bottomSheetVerificationWaitingItem {
|
||||||
id("waiting")
|
// id("waiting")
|
||||||
title(host.stringProvider.getString(R.string.please_wait))
|
// title(host.stringProvider.getString(R.string.please_wait))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun renderCancel(cancelCode: CancelCode) {
|
// private fun renderCancel(cancelCode: CancelCode) {
|
||||||
val host = this
|
// val host = this
|
||||||
when (cancelCode) {
|
// when (cancelCode) {
|
||||||
CancelCode.QrCodeInvalid -> {
|
// CancelCode.QrCodeInvalid -> {
|
||||||
// TODO
|
// // TODO
|
||||||
}
|
// }
|
||||||
CancelCode.MismatchedUser,
|
// CancelCode.MismatchedUser,
|
||||||
CancelCode.MismatchedSas,
|
// CancelCode.MismatchedSas,
|
||||||
CancelCode.MismatchedCommitment,
|
// CancelCode.MismatchedCommitment,
|
||||||
CancelCode.MismatchedKeys -> {
|
// CancelCode.MismatchedKeys -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verification_conclusion_not_secure).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verification_conclusion_not_secure).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationBigImageItem {
|
// bottomSheetVerificationBigImageItem {
|
||||||
id("image")
|
// id("image")
|
||||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Warning)
|
// roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Warning)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("warning_notice")
|
// id("warning_notice")
|
||||||
notice(host.eventHtmlRenderer.render(host.stringProvider.getString(R.string.verification_conclusion_compromised)).toEpoxyCharSequence())
|
// notice(host.eventHtmlRenderer.render(host.stringProvider.getString(R.string.verification_conclusion_compromised)).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else -> {
|
// else -> {
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice_cancelled")
|
// id("notice_cancelled")
|
||||||
notice(host.stringProvider.getString(R.string.verify_cancelled_notice).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verify_cancelled_notice).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun buildEmojiItem(emoji: List<EmojiRepresentation>) {
|
// private fun buildEmojiItem(emoji: List<EmojiRepresentation>) {
|
||||||
val host = this
|
// val host = this
|
||||||
bottomSheetVerificationNoticeItem {
|
// bottomSheetVerificationNoticeItem {
|
||||||
id("notice")
|
// id("notice")
|
||||||
notice(host.stringProvider.getString(R.string.verification_emoji_notice).toEpoxyCharSequence())
|
// notice(host.stringProvider.getString(R.string.verification_emoji_notice).toEpoxyCharSequence())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
bottomSheetVerificationEmojisItem {
|
// bottomSheetVerificationEmojisItem {
|
||||||
id("emojis")
|
// id("emojis")
|
||||||
emojiRepresentation0(emoji[0])
|
// emojiRepresentation0(emoji[0])
|
||||||
emojiRepresentation1(emoji[1])
|
// emojiRepresentation1(emoji[1])
|
||||||
emojiRepresentation2(emoji[2])
|
// emojiRepresentation2(emoji[2])
|
||||||
emojiRepresentation3(emoji[3])
|
// emojiRepresentation3(emoji[3])
|
||||||
emojiRepresentation4(emoji[4])
|
// emojiRepresentation4(emoji[4])
|
||||||
emojiRepresentation5(emoji[5])
|
// emojiRepresentation5(emoji[5])
|
||||||
emojiRepresentation6(emoji[6])
|
// emojiRepresentation6(emoji[6])
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
buildSasCodeActions()
|
// buildSasCodeActions()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private fun buildSasCodeActions() {
|
// private fun buildSasCodeActions() {
|
||||||
val host = this
|
// val host = this
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep0")
|
// id("sep0")
|
||||||
}
|
// }
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("ko")
|
// id("ko")
|
||||||
title(host.stringProvider.getString(R.string.verification_sas_do_not_match))
|
// title(host.stringProvider.getString(R.string.verification_sas_do_not_match))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
iconRes(R.drawable.ic_check_off)
|
// iconRes(R.drawable.ic_check_off)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
// listener { host.listener?.onDoNotMatchButtonTapped() }
|
// // listener { host.listener?.onDoNotMatchButtonTapped() }
|
||||||
}
|
// }
|
||||||
bottomSheetDividerItem {
|
// bottomSheetDividerItem {
|
||||||
id("sep1")
|
// id("sep1")
|
||||||
}
|
// }
|
||||||
bottomSheetVerificationActionItem {
|
// bottomSheetVerificationActionItem {
|
||||||
id("ok")
|
// id("ok")
|
||||||
title(host.stringProvider.getString(R.string.verification_sas_match))
|
// title(host.stringProvider.getString(R.string.verification_sas_match))
|
||||||
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
iconRes(R.drawable.ic_check_on)
|
// iconRes(R.drawable.ic_check_on)
|
||||||
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
// iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
// listener { host.listener?.onMatchButtonTapped() }
|
// // listener { host.listener?.onMatchButtonTapped() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,36 +1,36 @@
|
|||||||
/*
|
// /*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
// * Copyright (c) 2022 New Vector Ltd
|
||||||
*
|
// *
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
// * you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
// * You may obtain a copy of the License at
|
||||||
*
|
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
// * limitations under the License.
|
||||||
*/
|
// */
|
||||||
|
//
|
||||||
package im.vector.app.features.crypto.verification.transaction
|
// package im.vector.app.features.crypto.verification.transaction
|
||||||
|
//
|
||||||
import android.view.LayoutInflater
|
// import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
// import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
// import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
// import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
// import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
// import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.user.UserVerificationViewModel
|
// import im.vector.app.features.crypto.verification.user.UserVerificationViewModel
|
||||||
|
//
|
||||||
@AndroidEntryPoint
|
// @AndroidEntryPoint
|
||||||
class VerificationTransactionFragment : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>() {
|
// class VerificationTransactionFragment : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>() {
|
||||||
|
//
|
||||||
private val viewModel by parentFragmentViewModel(UserVerificationViewModel::class)
|
// private val viewModel by parentFragmentViewModel(UserVerificationViewModel::class)
|
||||||
|
//
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
// override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
// return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
@ -22,10 +22,6 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.airbnb.mvrx.Fail
|
|
||||||
import com.airbnb.mvrx.Loading
|
|
||||||
import com.airbnb.mvrx.Success
|
|
||||||
import com.airbnb.mvrx.Uninitialized
|
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
@ -34,15 +30,11 @@ import im.vector.app.core.extensions.commitTransaction
|
|||||||
import im.vector.app.core.extensions.toMvRxBundle
|
import im.vector.app.core.extensions.toMvRxBundle
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import im.vector.app.databinding.BottomSheetVerificationBinding
|
import im.vector.app.databinding.BottomSheetVerificationBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewEvents
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewEvents
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
|
||||||
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ package im.vector.app.features.crypto.verification.user
|
|||||||
|
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import com.airbnb.epoxy.EpoxyController
|
import com.airbnb.epoxy.EpoxyController
|
||||||
import com.airbnb.mvrx.Async
|
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
@ -43,8 +42,9 @@ import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
|
|||||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
import org.matrix.android.sdk.api.session.crypto.verification.QRCodeVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
import org.matrix.android.sdk.api.session.crypto.verification.SasTransactionState
|
||||||
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -63,6 +63,8 @@ class UserVerificationController @Inject constructor(
|
|||||||
fun onMatchButtonTapped()
|
fun onMatchButtonTapped()
|
||||||
fun openCamera()
|
fun openCamera()
|
||||||
fun doVerifyBySas()
|
fun doVerifyBySas()
|
||||||
|
fun onUserDeniesQrCodeScanned()
|
||||||
|
fun onUserConfirmsQrCodeScanned()
|
||||||
}
|
}
|
||||||
|
|
||||||
var listener: InteractionListener? = null
|
var listener: InteractionListener? = null
|
||||||
@ -169,7 +171,7 @@ class UserVerificationController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Fail -> {
|
is Fail -> {
|
||||||
//TODO
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,14 +259,98 @@ class UserVerificationController @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTransaction(state: UserVerificationViewState, transaction: VerificationTransactionData) {
|
private fun renderTransaction(state: UserVerificationViewState, transaction: VerificationTransactionData) {
|
||||||
|
when (transaction) {
|
||||||
|
is VerificationTransactionData.QrTransactionData -> {
|
||||||
|
renderQrTransaction(transaction, state.otherUserMxItem)
|
||||||
|
}
|
||||||
|
is VerificationTransactionData.SasTransactionData -> {
|
||||||
|
renderSasTransaction(transaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderQrTransaction(transaction: VerificationTransactionData.QrTransactionData, otherUserItem: MatrixItem) {
|
||||||
val host = this
|
val host = this
|
||||||
if (transaction.method == VerificationMethod.SAS) {
|
|
||||||
when (val txState = transaction.state) {
|
when (val txState = transaction.state) {
|
||||||
VerificationTxState.SasShortCodeReady -> {
|
QRCodeVerificationState.Reciprocated -> {
|
||||||
|
// we are waiting for confirmation from the other side
|
||||||
|
bottomSheetVerificationNoticeItem {
|
||||||
|
id("notice")
|
||||||
|
apply {
|
||||||
|
notice(host.stringProvider.getString(R.string.qr_code_scanned_verif_waiting_notice).toEpoxyCharSequence())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomSheetVerificationBigImageItem {
|
||||||
|
id("image")
|
||||||
|
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomSheetVerificationWaitingItem {
|
||||||
|
id("waiting")
|
||||||
|
title(host.stringProvider.getString(R.string.qr_code_scanned_verif_waiting, otherUserItem.getBestName()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QRCodeVerificationState.WaitingForScanConfirmation -> {
|
||||||
|
// we need to confirm that the other party actual scanned us
|
||||||
|
bottomSheetVerificationNoticeItem {
|
||||||
|
id("notice")
|
||||||
|
apply {
|
||||||
|
val name = otherUserItem.getBestName()
|
||||||
|
notice(host.stringProvider.getString(R.string.qr_code_scanned_by_other_notice, name).toEpoxyCharSequence())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomSheetVerificationBigImageItem {
|
||||||
|
id("image")
|
||||||
|
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomSheetDividerItem {
|
||||||
|
id("sep0")
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomSheetVerificationActionItem {
|
||||||
|
id("deny")
|
||||||
|
title(host.stringProvider.getString(R.string.qr_code_scanned_by_other_no))
|
||||||
|
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
|
iconRes(R.drawable.ic_check_off)
|
||||||
|
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorError))
|
||||||
|
listener { host.listener?.onUserDeniesQrCodeScanned() }
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomSheetDividerItem {
|
||||||
|
id("sep1")
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomSheetVerificationActionItem {
|
||||||
|
id("confirm")
|
||||||
|
title(host.stringProvider.getString(R.string.qr_code_scanned_by_other_yes))
|
||||||
|
titleColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
|
iconRes(R.drawable.ic_check_on)
|
||||||
|
iconColor(host.colorProvider.getColorFromAttribute(R.attr.colorPrimary))
|
||||||
|
listener { host.listener?.onUserConfirmsQrCodeScanned() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QRCodeVerificationState.WaitingForOtherDone,
|
||||||
|
QRCodeVerificationState.Done -> {
|
||||||
|
// Done
|
||||||
|
}
|
||||||
|
QRCodeVerificationState.Cancelled -> {
|
||||||
|
// Done
|
||||||
|
// renderCancel(transaction.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderSasTransaction(transaction: VerificationTransactionData.SasTransactionData) {
|
||||||
|
val host = this
|
||||||
|
when (val txState = transaction.state) {
|
||||||
|
SasTransactionState.SasShortCodeReady -> {
|
||||||
buildEmojiItem(transaction.emojiCodeRepresentation.orEmpty())
|
buildEmojiItem(transaction.emojiCodeRepresentation.orEmpty())
|
||||||
}
|
}
|
||||||
is VerificationTxState.SasMacReceived -> {
|
is SasTransactionState.SasMacReceived -> {
|
||||||
if(!txState.codeConfirmed) {
|
if (!txState.codeConfirmed) {
|
||||||
buildEmojiItem(transaction.emojiCodeRepresentation.orEmpty())
|
buildEmojiItem(transaction.emojiCodeRepresentation.orEmpty())
|
||||||
} else {
|
} else {
|
||||||
// waiting
|
// waiting
|
||||||
@ -274,8 +360,8 @@ class UserVerificationController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VerificationTxState.Cancelled,
|
is SasTransactionState.Cancelled,
|
||||||
is VerificationTxState.Done -> {
|
is SasTransactionState.Done -> {
|
||||||
// should show request status
|
// should show request status
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@ -286,9 +372,6 @@ class UserVerificationController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// TODO (QR CODe
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderCancel(cancelCode: CancelCode) {
|
private fun renderCancel(cancelCode: CancelCode) {
|
||||||
|
@ -140,4 +140,12 @@ class UserVerificationFragment : VectorBaseFragment<BottomSheetVerificationChild
|
|||||||
override fun doVerifyBySas() {
|
override fun doVerifyBySas() {
|
||||||
viewModel.handle(VerificationAction.StartSASVerification)
|
viewModel.handle(VerificationAction.StartSASVerification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onUserDeniesQrCodeScanned() {
|
||||||
|
viewModel.handle(VerificationAction.OtherUserDidNotScanned)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUserConfirmsQrCodeScanned() {
|
||||||
|
viewModel.handle(VerificationAction.OtherUserScannedSuccessfully)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ import im.vector.app.features.crypto.verification.SupportedVerificationMethodsPr
|
|||||||
import im.vector.app.features.crypto.verification.VerificationAction
|
import im.vector.app.features.crypto.verification.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewEvents
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewEvents
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.forEach
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -44,14 +43,13 @@ import org.matrix.android.sdk.api.extensions.orFalse
|
|||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.IVerificationRequest
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.QRCodeVerificationState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.verification.SasTransactionState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.getRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.getRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.getTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.getTransaction
|
||||||
import org.matrix.android.sdk.api.session.getUser
|
import org.matrix.android.sdk.api.session.getUser
|
||||||
@ -82,25 +80,52 @@ data class UserVerificationViewState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We need immutable objects to use properly in MvrxState
|
// We need immutable objects to use properly in MvrxState
|
||||||
data class VerificationTransactionData(
|
sealed class VerificationTransactionData(
|
||||||
val transactionId: String,
|
open val transactionId: String,
|
||||||
val state: VerificationTxState,
|
open val otherUserId: String,
|
||||||
val method: VerificationMethod,
|
) {
|
||||||
val otherUserId: String,
|
|
||||||
|
data class SasTransactionData(
|
||||||
|
override val transactionId: String,
|
||||||
|
val state: SasTransactionState,
|
||||||
|
override val otherUserId: String,
|
||||||
val otherDeviceId: String?,
|
val otherDeviceId: String?,
|
||||||
val isIncoming: Boolean,
|
val isIncoming: Boolean,
|
||||||
val emojiCodeRepresentation: List<EmojiRepresentation>?
|
val emojiCodeRepresentation: List<EmojiRepresentation>?
|
||||||
)
|
) : VerificationTransactionData(transactionId, otherUserId)
|
||||||
fun VerificationTransaction.toDataClass() : VerificationTransactionData {
|
|
||||||
return VerificationTransactionData(
|
data class QrTransactionData(
|
||||||
|
override val transactionId: String,
|
||||||
|
val state: QRCodeVerificationState,
|
||||||
|
override val otherUserId: String,
|
||||||
|
val otherDeviceId: String?,
|
||||||
|
val isIncoming: Boolean,
|
||||||
|
) : VerificationTransactionData(transactionId, otherUserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun VerificationTransaction.toDataClass(): VerificationTransactionData? {
|
||||||
|
return when (this) {
|
||||||
|
is SasVerificationTransaction -> {
|
||||||
|
VerificationTransactionData.SasTransactionData(
|
||||||
transactionId = this.transactionId,
|
transactionId = this.transactionId,
|
||||||
state = this.state,
|
state = this.state(),
|
||||||
method = this.method,
|
|
||||||
otherUserId = this.otherUserId,
|
otherUserId = this.otherUserId,
|
||||||
otherDeviceId = this.otherUserId,
|
otherDeviceId = this.otherDeviceId,
|
||||||
isIncoming = this.isIncoming,
|
isIncoming = this.isIncoming,
|
||||||
emojiCodeRepresentation = (this as? SasVerificationTransaction)?.getEmojiCodeRepresentation()
|
emojiCodeRepresentation = this.getEmojiCodeRepresentation()
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
is QrCodeVerificationTransaction -> {
|
||||||
|
VerificationTransactionData.QrTransactionData(
|
||||||
|
transactionId = this.transactionId,
|
||||||
|
state = this.state(),
|
||||||
|
otherUserId = this.otherUserId,
|
||||||
|
otherDeviceId = this.otherDeviceId,
|
||||||
|
isIncoming = this.isIncoming,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserVerificationViewModel @AssistedInject constructor(
|
class UserVerificationViewModel @AssistedInject constructor(
|
||||||
@ -127,8 +152,8 @@ class UserVerificationViewModel @AssistedInject constructor(
|
|||||||
session.cryptoService().verificationService()
|
session.cryptoService().verificationService()
|
||||||
.requestEventFlow()
|
.requestEventFlow()
|
||||||
.filter {
|
.filter {
|
||||||
it.transactionId == currentTransactionId
|
it.transactionId == currentTransactionId ||
|
||||||
|| currentTransactionId == null && initialState.otherUserId == it.getRequest()?.otherUserId
|
currentTransactionId == null && initialState.otherUserId == it.getRequest()?.otherUserId
|
||||||
}
|
}
|
||||||
.onEach {
|
.onEach {
|
||||||
Timber.w("VALR update event ${it.getRequest()} ")
|
Timber.w("VALR update event ${it.getRequest()} ")
|
||||||
@ -142,11 +167,20 @@ class UserVerificationViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
it.getTransaction()?.let {
|
it.getTransaction()?.let {
|
||||||
Timber.w("VALR state updated transaction to $it")
|
Timber.w("VALR state updated transaction to $it")
|
||||||
|
val dClass = it.toDataClass()
|
||||||
|
if (dClass != null) {
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
startedTransaction = Success(it.toDataClass()),
|
startedTransaction = Success(dClass),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
startedTransaction = Fail(IllegalArgumentException("Unsupported Transaction")),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
@ -229,8 +263,30 @@ class UserVerificationViewModel @AssistedInject constructor(
|
|||||||
is VerificationAction.GotResultFromSsss -> {
|
is VerificationAction.GotResultFromSsss -> {
|
||||||
// not applicable, only for self verification
|
// not applicable, only for self verification
|
||||||
}
|
}
|
||||||
VerificationAction.OtherUserDidNotScanned -> TODO()
|
VerificationAction.OtherUserDidNotScanned -> {
|
||||||
VerificationAction.OtherUserScannedSuccessfully -> TODO()
|
withState { state ->
|
||||||
|
state.startedTransaction.invoke()?.let {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val tx = session.cryptoService().verificationService()
|
||||||
|
.getExistingTransaction(it.otherUserId, it.transactionId)
|
||||||
|
as? QrCodeVerificationTransaction
|
||||||
|
tx?.otherUserDidNotScannedMyQrCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VerificationAction.OtherUserScannedSuccessfully -> {
|
||||||
|
withState { state ->
|
||||||
|
state.startedTransaction.invoke()?.let {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val tx = session.cryptoService().verificationService()
|
||||||
|
.getExistingTransaction(it.otherUserId, it.transactionId)
|
||||||
|
as? QrCodeVerificationTransaction
|
||||||
|
tx?.otherUserScannedMyQrCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
VerificationAction.ReadyPendingVerification -> {
|
VerificationAction.ReadyPendingVerification -> {
|
||||||
withState { state ->
|
withState { state ->
|
||||||
state.pendingRequest.invoke()?.let {
|
state.pendingRequest.invoke()?.let {
|
||||||
@ -244,13 +300,34 @@ class UserVerificationViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VerificationAction.RemoteQrCodeScanned -> TODO()
|
is VerificationAction.RemoteQrCodeScanned -> {
|
||||||
|
setState {
|
||||||
|
copy(startedTransaction = Loading())
|
||||||
|
}
|
||||||
|
withState { state ->
|
||||||
|
val request = state.pendingRequest.invoke() ?: return@withState
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
session.cryptoService().verificationService()
|
||||||
|
.reciprocateQRVerification(
|
||||||
|
request.otherUserId,
|
||||||
|
request.transactionId,
|
||||||
|
action.scannedData
|
||||||
|
)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.w(failure, "Failed to reciprocated")
|
||||||
|
setState {
|
||||||
|
copy(startedTransaction = Fail(failure))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
is VerificationAction.RequestVerificationByDM -> {
|
is VerificationAction.RequestVerificationByDM -> {
|
||||||
setState {
|
setState {
|
||||||
copy(pendingRequest = Loading())
|
copy(pendingRequest = Loading())
|
||||||
}
|
}
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|
||||||
// TODO if self verif we should do via DM
|
// TODO if self verif we should do via DM
|
||||||
val roomId = session.roomService().getExistingDirectRoomWithUser(initialState.otherUserId)
|
val roomId = session.roomService().getExistingDirectRoomWithUser(initialState.otherUserId)
|
||||||
?: session.roomService().createDirectRoom(initialState.otherUserId)
|
?: session.roomService().createDirectRoom(initialState.otherUserId)
|
||||||
@ -266,14 +343,12 @@ class UserVerificationViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
Timber.w("VALR started request is $request")
|
Timber.w("VALR started request is $request")
|
||||||
|
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
pendingRequest = Success(request),
|
pendingRequest = Success(request),
|
||||||
transactionId = request.transactionId
|
transactionId = request.transactionId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VerificationAction.SASDoNotMatchAction -> {
|
is VerificationAction.SASDoNotMatchAction -> {
|
||||||
|
@ -265,7 +265,7 @@ class HomeActivity :
|
|||||||
HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush()
|
HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush()
|
||||||
HomeActivityViewEvents.StartRecoverySetupFlow -> handleStartRecoverySetup()
|
HomeActivityViewEvents.StartRecoverySetupFlow -> handleStartRecoverySetup()
|
||||||
is HomeActivityViewEvents.ForceVerification -> {
|
is HomeActivityViewEvents.ForceVerification -> {
|
||||||
//TODO
|
// TODO
|
||||||
// if (it.sendRequest) {
|
// if (it.sendRequest) {
|
||||||
navigator.requestSelfSessionVerification(this)
|
navigator.requestSelfSessionVerification(this)
|
||||||
// } else {
|
// } else {
|
||||||
|
@ -124,7 +124,6 @@ import im.vector.app.features.call.conference.ConferenceEventObserver
|
|||||||
import im.vector.app.features.call.conference.JitsiCallViewModel
|
import im.vector.app.features.call.conference.JitsiCallViewModel
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
|
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|
||||||
import im.vector.app.features.crypto.verification.user.UserVerificationBottomSheet
|
import im.vector.app.features.crypto.verification.user.UserVerificationBottomSheet
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||||
|
@ -52,7 +52,6 @@ import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
|
|||||||
import im.vector.app.features.crypto.recover.BootstrapBottomSheet
|
import im.vector.app.features.crypto.recover.BootstrapBottomSheet
|
||||||
import im.vector.app.features.crypto.recover.SetupMode
|
import im.vector.app.features.crypto.recover.SetupMode
|
||||||
import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider
|
import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|
||||||
import im.vector.app.features.devtools.RoomDevToolActivity
|
import im.vector.app.features.devtools.RoomDevToolActivity
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||||
|
@ -50,7 +50,6 @@ import im.vector.app.databinding.DialogShareQrCodeBinding
|
|||||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||||
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
|
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
|
||||||
import im.vector.app.features.analytics.plan.MobileScreen
|
import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|
||||||
import im.vector.app.features.crypto.verification.user.UserVerificationBottomSheet
|
import im.vector.app.features.crypto.verification.user.UserVerificationBottomSheet
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
@ -31,7 +31,6 @@ import im.vector.app.R
|
|||||||
import im.vector.app.core.extensions.commitTransaction
|
import im.vector.app.core.extensions.commitTransaction
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import im.vector.app.databinding.BottomSheetWithFragmentsBinding
|
import im.vector.app.databinding.BottomSheetWithFragmentsBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ -50,11 +49,12 @@ class DeviceListBottomSheet :
|
|||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is DeviceListBottomSheetViewEvents.Verify -> {
|
is DeviceListBottomSheetViewEvents.Verify -> {
|
||||||
VerificationBottomSheet.withArgs(
|
// TODO selfverif
|
||||||
// roomId = null,
|
// VerificationBottomSheet.withArgs(
|
||||||
otherUserId = it.userId,
|
// // roomId = null,
|
||||||
transactionId = it.txID
|
// otherUserId = it.userId,
|
||||||
).show(requireActivity().supportFragmentManager, "REQPOP")
|
// transactionId = it.txID
|
||||||
|
// ).show(requireActivity().supportFragmentManager, "REQPOP")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,6 @@ import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
|||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
|
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
|
||||||
import org.matrix.android.sdk.flow.flow
|
import org.matrix.android.sdk.flow.flow
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -126,7 +125,7 @@ class DevicesViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
session.cryptoService().verificationService().requestEventFlow()
|
session.cryptoService().verificationService().requestEventFlow()
|
||||||
.onEach {
|
.onEach {
|
||||||
when(it) {
|
when (it) {
|
||||||
is VerificationEvent.RequestUpdated -> {
|
is VerificationEvent.RequestUpdated -> {
|
||||||
if (it.request.isFinished) {
|
if (it.request.isFinished) {
|
||||||
queryRefreshDevicesList()
|
queryRefreshDevicesList()
|
||||||
@ -241,7 +240,7 @@ class DevicesViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun transactionUpdated(tx: VerificationTransaction) {
|
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||||
if (tx.state == VerificationTxState.Verified) {
|
if (tx.isSuccessful()) {
|
||||||
queryRefreshDevicesList()
|
queryRefreshDevicesList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ import im.vector.app.databinding.DialogBaseEditTextBinding
|
|||||||
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||||
import im.vector.app.features.auth.ReAuthActivity
|
import im.vector.app.features.auth.ReAuthActivity
|
||||||
import im.vector.app.features.crypto.recover.SetupMode
|
import im.vector.app.features.crypto.recover.SetupMode
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|
||||||
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -78,11 +77,12 @@ class VectorSettingsDevicesFragment :
|
|||||||
is DevicesViewEvents.RequestReAuth -> askForReAuthentication(it)
|
is DevicesViewEvents.RequestReAuth -> askForReAuthentication(it)
|
||||||
is DevicesViewEvents.PromptRenameDevice -> displayDeviceRenameDialog(it.deviceInfo)
|
is DevicesViewEvents.PromptRenameDevice -> displayDeviceRenameDialog(it.deviceInfo)
|
||||||
is DevicesViewEvents.ShowVerifyDevice -> {
|
is DevicesViewEvents.ShowVerifyDevice -> {
|
||||||
VerificationBottomSheet.withArgs(
|
// TODO selfverif
|
||||||
// roomId = null,
|
// VerificationBottomSheet.withArgs(
|
||||||
otherUserId = it.userId,
|
// // roomId = null,
|
||||||
transactionId = it.transactionId ?: ""
|
// otherUserId = it.userId,
|
||||||
).show(childFragmentManager, "REQPOP")
|
// transactionId = it.transactionId ?: ""
|
||||||
|
// ).show(childFragmentManager, "REQPOP")
|
||||||
}
|
}
|
||||||
is DevicesViewEvents.SelfVerification -> {
|
is DevicesViewEvents.SelfVerification -> {
|
||||||
navigator.requestSelfSessionVerification(requireActivity())
|
navigator.requestSelfSessionVerification(requireActivity())
|
||||||
|
@ -25,11 +25,9 @@ import im.vector.app.core.utils.PublishDataSource
|
|||||||
import im.vector.lib.core.utils.flow.throttleFirst
|
import im.vector.lib.core.utils.flow.throttleFirst
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
abstract class VectorSessionsListViewModel<S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents>(
|
abstract class VectorSessionsListViewModel<S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents>(
|
||||||
@ -85,7 +83,7 @@ abstract class VectorSessionsListViewModel<S : MavericksState, VA : VectorViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun transactionUpdated(tx: VerificationTransaction) {
|
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||||
if (tx.state == VerificationTxState.Verified) {
|
if (tx.isSuccessful()) {
|
||||||
refreshDeviceList()
|
refreshDeviceList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ import im.vector.app.core.resources.DrawableProvider
|
|||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.databinding.FragmentSettingsDevicesBinding
|
import im.vector.app.databinding.FragmentSettingsDevicesBinding
|
||||||
import im.vector.app.features.crypto.recover.SetupMode
|
import im.vector.app.features.crypto.recover.SetupMode
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
import im.vector.app.features.settings.devices.v2.list.NUMBER_OF_OTHER_DEVICES_TO_RENDER
|
import im.vector.app.features.settings.devices.v2.list.NUMBER_OF_OTHER_DEVICES_TO_RENDER
|
||||||
import im.vector.app.features.settings.devices.v2.list.OtherSessionsView
|
import im.vector.app.features.settings.devices.v2.list.OtherSessionsView
|
||||||
@ -98,11 +97,12 @@ class VectorSettingsDevicesFragment :
|
|||||||
is DevicesViewEvent.RequestReAuth -> Unit // TODO. Next PR
|
is DevicesViewEvent.RequestReAuth -> Unit // TODO. Next PR
|
||||||
is DevicesViewEvent.PromptRenameDevice -> Unit // TODO. Next PR
|
is DevicesViewEvent.PromptRenameDevice -> Unit // TODO. Next PR
|
||||||
is DevicesViewEvent.ShowVerifyDevice -> {
|
is DevicesViewEvent.ShowVerifyDevice -> {
|
||||||
VerificationBottomSheet.withArgs(
|
// TODO selfverif
|
||||||
// roomId = null,
|
// VerificationBottomSheet.withArgs(
|
||||||
otherUserId = it.userId,
|
// // roomId = null,
|
||||||
transactionId = it.transactionId ?:""
|
// otherUserId = it.userId,
|
||||||
).show(childFragmentManager, "REQPOP")
|
// transactionId = it.transactionId ?:""
|
||||||
|
// ).show(childFragmentManager, "REQPOP")
|
||||||
}
|
}
|
||||||
is DevicesViewEvent.SelfVerification -> {
|
is DevicesViewEvent.SelfVerification -> {
|
||||||
navigator.requestSelfSessionVerification(requireActivity())
|
navigator.requestSelfSessionVerification(requireActivity())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user