diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 79ee123c2b..6e6eec1148 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,6 @@
+
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt
index c2a847dd0b..a626dd5573 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt
@@ -44,22 +44,18 @@ interface SasVerificationService {
fun getExistingVerificationRequest(otherUser: String, tid: String?): PendingVerificationRequest?
- /**
- * Shortcut for KeyVerificationStart.VERIF_METHOD_SAS
- * @see beginKeyVerification
- */
- fun beginKeyVerificationSAS(userId: String, deviceID: String): String?
+ fun getExistingVerificationRequestInRoom(roomId: String, tid: String?): PendingVerificationRequest?
+
+ fun beginKeyVerification(method: VerificationMethod, userId: String, deviceID: String): String?
/**
* Request a key verification from another user using toDevice events.
*/
- fun beginKeyVerification(method: String, userId: String, deviceID: String): String?
-
- fun requestKeyVerificationInDMs(userId: String, roomId: String): PendingVerificationRequest
+ fun requestKeyVerificationInDMs(methods: List, userId: String, roomId: String): PendingVerificationRequest
fun declineVerificationRequestInDMs(otherUserId: String, otherDeviceId: String, transactionId: String, roomId: String)
- fun beginKeyVerificationInDMs(method: String,
+ fun beginKeyVerificationInDMs(method: VerificationMethod,
transactionId: String,
roomId: String,
otherUserId: String,
@@ -67,7 +63,7 @@ interface SasVerificationService {
callback: MatrixCallback?): String?
/**
- * Returns false if the request is unknwown
+ * Returns false if the request is unknown
*/
fun readyPendingVerificationInDMs(otherUserId: String, roomId: String, transactionId: String): Boolean
@@ -84,14 +80,14 @@ interface SasVerificationService {
companion object {
- private const val TEN_MINTUTES_IN_MILLIS = 10 * 60 * 1000
- private const val FIVE_MINTUTES_IN_MILLIS = 5 * 60 * 1000
+ private const val TEN_MINUTES_IN_MILLIS = 10 * 60 * 1000
+ private const val FIVE_MINUTES_IN_MILLIS = 5 * 60 * 1000
fun isValidRequest(age: Long?): Boolean {
if (age == null) return false
val now = System.currentTimeMillis()
- val tooInThePast = now - TEN_MINTUTES_IN_MILLIS
- val tooInTheFuture = now + FIVE_MINTUTES_IN_MILLIS
+ val tooInThePast = now - TEN_MINUTES_IN_MILLIS
+ val tooInTheFuture = now + FIVE_MINUTES_IN_MILLIS
return age in tooInThePast..tooInTheFuture
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/VerificationMethod.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/VerificationMethod.kt
new file mode 100644
index 0000000000..a2dd90bc84
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/VerificationMethod.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.api.session.crypto.sas
+
+/**
+ * Verification methods supported (or to be supported) by the matrix SDK
+ */
+enum class VerificationMethod {
+ SAS,
+ // Not supported yet
+ SCAN
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationStartContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationStartContent.kt
index a33decc821..dffa4ba3cb 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationStartContent.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageVerificationStartContent.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.session.crypto.sas.SasMode
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultContent
-import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
+import im.vector.matrix.android.internal.crypto.model.rest.supportedVerificationMethods
import im.vector.matrix.android.internal.crypto.verification.SASVerificationTransaction
import im.vector.matrix.android.internal.crypto.verification.VerificationInfoStart
import im.vector.matrix.android.internal.util.JsonCanonicalizer
@@ -45,12 +45,11 @@ internal data class MessageVerificationStartContent(
get() = relatesTo?.eventId
override fun isValid(): Boolean {
- if (
- (transactionID.isNullOrBlank()
- || fromDevice.isNullOrBlank()
- || method != KeyVerificationStart.VERIF_METHOD_SAS
- || keyAgreementProtocols.isNullOrEmpty()
- || hashes.isNullOrEmpty())
+ if (transactionID.isNullOrBlank()
+ || fromDevice.isNullOrBlank()
+ || method !in supportedVerificationMethods
+ || keyAgreementProtocols.isNullOrEmpty()
+ || hashes.isNullOrEmpty()
|| !hashes.contains("sha256") || messageAuthenticationCodes.isNullOrEmpty()
|| (!messageAuthenticationCodes.contains(SASVerificationTransaction.SAS_MAC_SHA256)
&& !messageAuthenticationCodes.contains(SASVerificationTransaction.SAS_MAC_SHA256_LONGKDF))
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationReady.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationReady.kt
index ca3b1e0075..84bc73fda0 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationReady.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationReady.kt
@@ -25,8 +25,7 @@ import im.vector.matrix.android.internal.crypto.verification.VerificationInfoRea
@JsonClass(generateAdapter = true)
internal data class KeyVerificationReady(
@Json(name = "from_device") override val fromDevice: String?,
- // TODO add qr?
- @Json(name = "methods") override val methods: List? = listOf(KeyVerificationStart.VERIF_METHOD_SAS),
+ @Json(name = "methods") override val methods: List?,
@Json(name = "transaction_id") override var transactionID: String? = null
) : SendToDeviceObject, VerificationInfoReady {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationRequest.kt
index 4511db324a..0af7b45b70 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationRequest.kt
@@ -28,7 +28,7 @@ internal data class KeyVerificationRequest(
@Json(name = "from_device")
val fromDevice: String,
/** The verification methods supported by the sender. */
- val methods: List = listOf(KeyVerificationStart.VERIF_METHOD_SAS),
+ val methods: List,
/**
* The POSIX timestamp in milliseconds for when the request was made.
* If the request is in the future by more than 5 minutes or more than 10 minutes in the past,
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt
index e25ed10a6a..fa4ec3acfa 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/KeyVerificationStart.kt
@@ -27,7 +27,7 @@ import timber.log.Timber
* Sent by Alice to initiate an interactive key verification.
*/
@JsonClass(generateAdapter = true)
-data class KeyVerificationStart(
+internal data class KeyVerificationStart(
@Json(name = "from_device") override val fromDevice: String? = null,
override val method: String? = null,
@Json(name = "transaction_id") override val transactionID: String? = null,
@@ -41,22 +41,18 @@ data class KeyVerificationStart(
return JsonCanonicalizer.getCanonicalJson(KeyVerificationStart::class.java, this)
}
- companion object {
- const val VERIF_METHOD_SAS = "m.sas.v1"
- const val VERIF_METHOD_SCAN = "m.qr_code.scan.v1"
- }
-
override fun isValid(): Boolean {
- if ((transactionID.isNullOrBlank()
- || fromDevice.isNullOrBlank()
- || method != VERIF_METHOD_SAS
- || keyAgreementProtocols.isNullOrEmpty()
- || hashes.isNullOrEmpty())
+ if (transactionID.isNullOrBlank()
+ || fromDevice.isNullOrBlank()
+ || method !in supportedVerificationMethods
+ || keyAgreementProtocols.isNullOrEmpty()
+ || hashes.isNullOrEmpty()
|| !hashes.contains("sha256")
|| messageAuthenticationCodes.isNullOrEmpty()
|| (!messageAuthenticationCodes.contains(SASVerificationTransaction.SAS_MAC_SHA256)
&& !messageAuthenticationCodes.contains(SASVerificationTransaction.SAS_MAC_SHA256_LONGKDF))
- || shortAuthenticationStrings.isNullOrEmpty() || !shortAuthenticationStrings.contains(SasMode.DECIMAL)) {
+ || shortAuthenticationStrings.isNullOrEmpty()
+ || !shortAuthenticationStrings.contains(SasMode.DECIMAL)) {
Timber.e("## received invalid verification request")
return false
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/VerificationMethodValues.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/VerificationMethodValues.kt
new file mode 100644
index 0000000000..168a8c8f48
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/rest/VerificationMethodValues.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.crypto.model.rest
+
+import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
+
+internal const val VERIFICATION_METHOD_SAS = "m.sas.v1"
+internal const val VERIFICATION_METHOD_SCAN = "m.qr_code.scan.v1"
+
+internal fun VerificationMethod.toValue(): String {
+ return when (this) {
+ VerificationMethod.SAS -> VERIFICATION_METHOD_SAS
+ VerificationMethod.SCAN -> VERIFICATION_METHOD_SCAN
+ }
+}
+
+// TODO Add SCAN
+internal val supportedVerificationMethods = listOf(VERIFICATION_METHOD_SAS)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt
index 2167940aaa..c285f16ee3 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt
@@ -104,6 +104,7 @@ internal class DefaultRoomVerificationUpdateTask @Inject constructor(
// The verification is started from another device
Timber.v("## SAS Verification live observer: Transaction started by other device tid:${it.transactionID} ")
it.transactionID?.let { txId -> transactionsHandledByOtherDevice.add(txId) }
+ params.sasVerificationService.onRoomRequestHandledByOtherDevice(event)
}
}
} else if (EventType.KEY_VERIFICATION_READY == event.type) {
@@ -112,11 +113,13 @@ internal class DefaultRoomVerificationUpdateTask @Inject constructor(
// The verification is started from another device
Timber.v("## SAS Verification live observer: Transaction started by other device tid:${it.transactionID} ")
it.transactionID?.let { txId -> transactionsHandledByOtherDevice.add(txId) }
+ params.sasVerificationService.onRoomRequestHandledByOtherDevice(event)
}
}
} else if (EventType.KEY_VERIFICATION_CANCEL == event.type || EventType.KEY_VERIFICATION_DONE == event.type) {
event.getClearContent().toModel()?.relatesTo?.eventId?.let {
transactionsHandledByOtherDevice.remove(it)
+ params.sasVerificationService.onRoomRequestHandledByOtherDevice(event)
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASVerificationRequest.kt
index 5eead70c17..6e6f55b9fb 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASVerificationRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASVerificationRequest.kt
@@ -19,9 +19,10 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
+import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
-import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
+import im.vector.matrix.android.internal.crypto.model.rest.toValue
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import timber.log.Timber
@@ -71,7 +72,7 @@ internal class DefaultOutgoingSASVerificationRequest(
cancel(CancelCode.UnexpectedMessage)
}
- fun start() {
+ fun start(method: VerificationMethod) {
if (state != SasVerificationTxState.None) {
Timber.e("## SAS O: start verification from invalid state")
// should I cancel??
@@ -80,7 +81,7 @@ internal class DefaultOutgoingSASVerificationRequest(
val startMessage = transport.createStart(
credentials.deviceId ?: "",
- KeyVerificationStart.VERIF_METHOD_SAS,
+ method.toValue(),
transactionId,
KNOWN_AGREEMENT_PROTOCOLS,
KNOWN_HASHES,
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
index f5075cbb23..8fa91e2f4a 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
@@ -22,10 +22,7 @@ import dagger.Lazy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.crypto.CryptoService
-import im.vector.matrix.android.api.session.crypto.sas.CancelCode
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
-import im.vector.matrix.android.api.session.crypto.sas.safeValueOf
+import im.vector.matrix.android.api.session.crypto.sas.*
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.LocalEcho
@@ -216,7 +213,20 @@ internal class DefaultSasVerificationService @Inject constructor(
}
}
- fun onRoomRequestReceived(event: Event) {
+ fun onRoomRequestHandledByOtherDevice(event: Event) {
+ val requestInfo = event.getClearContent().toModel()
+ ?: return
+ val requestId = requestInfo.relatesTo?.eventId ?: return
+ getExistingVerificationRequestInRoom(event.roomId ?: "", requestId)?.let {
+ updatePendingRequest(
+ it.copy(
+ handledByOtherSession = true
+ )
+ )
+ }
+ }
+
+ suspend fun onRoomRequestReceived(event: Event) {
Timber.v("## SAS Verification request from ${event.senderId} in room ${event.roomId}")
val requestInfo = event.getClearContent().toModel()
?: return
@@ -245,6 +255,7 @@ internal class DefaultSasVerificationService @Inject constructor(
ageLocalTs = event.ageLocalTs ?: System.currentTimeMillis(),
isIncoming = true,
otherUserId = senderId, // requestInfo.toUserId,
+ roomId = event.roomId,
transactionId = event.eventId,
requestInfo = requestInfo
)
@@ -274,31 +285,27 @@ internal class DefaultSasVerificationService @Inject constructor(
if (startReq?.isValid()?.not() == true) {
Timber.e("## received invalid verification request")
if (startReq.transactionID != null) {
- sasTransportRoomMessageFactory.createTransport(credentials.userId, credentials.deviceId
- ?: "", event.roomId
- ?: "", null).cancelTransaction(
- startReq.transactionID ?: "",
- otherUserId!!,
- startReq.fromDevice ?: event.getSenderKey()!!,
- CancelCode.UnknownMethod
- )
+ sasTransportRoomMessageFactory.createTransport(event.roomId ?: "", null)
+ .cancelTransaction(
+ startReq.transactionID ?: "",
+ otherUserId!!,
+ startReq.fromDevice ?: event.getSenderKey()!!,
+ CancelCode.UnknownMethod
+ )
}
return
}
handleStart(otherUserId, startReq as VerificationInfoStart) {
- it.transport = sasTransportRoomMessageFactory.createTransport(credentials.userId, credentials.deviceId
- ?: "", event.roomId
- ?: "", it)
+ it.transport = sasTransportRoomMessageFactory.createTransport(event.roomId ?: "", it)
}?.let {
- sasTransportRoomMessageFactory.createTransport(credentials.userId, credentials.deviceId
- ?: "", event.roomId
- ?: "", null).cancelTransaction(
- startReq.transactionID ?: "",
- otherUserId!!,
- startReq.fromDevice ?: event.getSenderKey()!!,
- it
- )
+ sasTransportRoomMessageFactory.createTransport(event.roomId ?: "", null)
+ .cancelTransaction(
+ startReq.transactionID ?: "",
+ otherUserId!!,
+ startReq.fromDevice ?: event.getSenderKey()!!,
+ it
+ )
}
}
@@ -356,7 +363,7 @@ internal class DefaultSasVerificationService @Inject constructor(
// cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
} else {
// Ok we can create
- if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) {
+ if (startReq.method == VERIFICATION_METHOD_SAS) {
Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
// If there is a corresponding request, we can auto accept
// as we are the one requesting in first place (or we accepted the request)
@@ -647,6 +654,16 @@ internal class DefaultSasVerificationService @Inject constructor(
}
}
+ override fun getExistingVerificationRequestInRoom(roomId: String, tid: String?): PendingVerificationRequest? {
+ synchronized(lock = pendingRequests) {
+ return tid?.let { tid ->
+ pendingRequests.flatMap { entry ->
+ entry.value.filter { it.roomId == roomId && it.transactionId == tid }
+ }.firstOrNull()
+ }
+ }
+ }
+
private fun getExistingTransactionsForUser(otherUser: String): Collection? {
synchronized(txMap) {
return txMap[otherUser]?.values
@@ -670,14 +687,10 @@ internal class DefaultSasVerificationService @Inject constructor(
}
}
- override fun beginKeyVerificationSAS(userId: String, deviceID: String): String? {
- return beginKeyVerification(KeyVerificationStart.VERIF_METHOD_SAS, userId, deviceID)
- }
-
- override fun beginKeyVerification(method: String, userId: String, deviceID: String): String? {
+ override fun beginKeyVerification(method: VerificationMethod, userId: String, deviceID: String): String? {
val txID = createUniqueIDForTransaction(userId, deviceID)
// should check if already one (and cancel it)
- if (KeyVerificationStart.VERIF_METHOD_SAS == method) {
+ if (method == VerificationMethod.SAS) {
val tx = DefaultOutgoingSASVerificationRequest(
setDeviceVerificationAction,
credentials,
@@ -689,14 +702,14 @@ internal class DefaultSasVerificationService @Inject constructor(
tx.transport = sasTransportToDeviceFactory.createTransport(tx)
addTransaction(tx)
- tx.start()
+ tx.start(method)
return txID
} else {
throw IllegalArgumentException("Unknown verification method")
}
}
- override fun requestKeyVerificationInDMs(userId: String, roomId: String)
+ override fun requestKeyVerificationInDMs(methods: List, userId: String, roomId: String)
: PendingVerificationRequest {
Timber.i("## SAS Requesting verification to user: $userId in room $roomId")
@@ -705,8 +718,7 @@ internal class DefaultSasVerificationService @Inject constructor(
pendingRequests[userId] = it
}
- val transport = sasTransportRoomMessageFactory.createTransport(credentials.userId, credentials.deviceId
- ?: "", roomId, null)
+ val transport = sasTransportRoomMessageFactory.createTransport(roomId, null)
// Cancel existing pending requests?
requestsForUser.forEach { existingRequest ->
@@ -723,11 +735,12 @@ internal class DefaultSasVerificationService @Inject constructor(
val verificationRequest = PendingVerificationRequest(
ageLocalTs = System.currentTimeMillis(),
isIncoming = false,
+ roomId = roomId,
localID = localID,
otherUserId = userId
)
- transport.sendVerificationRequest(localID, userId, roomId) { syncedId, info ->
+ transport.sendVerificationRequest(methods.map { it.toValue() }, localID, userId, roomId) { syncedId, info ->
// We need to update with the syncedID
updatePendingRequest(verificationRequest.copy(
transactionId = syncedId,
@@ -742,8 +755,8 @@ internal class DefaultSasVerificationService @Inject constructor(
}
override fun declineVerificationRequestInDMs(otherUserId: String, otherDeviceId: String, transactionId: String, roomId: String) {
- sasTransportRoomMessageFactory.createTransport(credentials.userId, credentials.deviceId
- ?: "", roomId, null).cancelTransaction(transactionId, otherUserId, otherDeviceId, CancelCode.User)
+ sasTransportRoomMessageFactory.createTransport(roomId, null)
+ .cancelTransaction(transactionId, otherUserId, otherDeviceId, CancelCode.User)
getExistingVerificationRequest(otherUserId, transactionId)?.let {
updatePendingRequest(it.copy(
@@ -768,10 +781,13 @@ internal class DefaultSasVerificationService @Inject constructor(
dispatchRequestUpdated(updated)
}
- override fun beginKeyVerificationInDMs(method: String, transactionId: String, roomId: String,
- otherUserId: String, otherDeviceId: String,
+ override fun beginKeyVerificationInDMs(method: VerificationMethod,
+ transactionId: String,
+ roomId: String,
+ otherUserId: String,
+ otherDeviceId: String,
callback: MatrixCallback?): String? {
- if (KeyVerificationStart.VERIF_METHOD_SAS == method) {
+ if (method == VerificationMethod.SAS) {
val tx = DefaultOutgoingSASVerificationRequest(
setDeviceVerificationAction,
credentials,
@@ -780,11 +796,10 @@ internal class DefaultSasVerificationService @Inject constructor(
transactionId,
otherUserId,
otherDeviceId)
- tx.transport = sasTransportRoomMessageFactory.createTransport(credentials.userId, credentials.deviceId
- ?: "", roomId, tx)
+ tx.transport = sasTransportRoomMessageFactory.createTransport(roomId, tx)
addTransaction(tx)
- tx.start()
+ tx.start(method)
return transactionId
} else {
throw IllegalArgumentException("Unknown verification method")
@@ -797,9 +812,8 @@ internal class DefaultSasVerificationService @Inject constructor(
val existingRequest = getExistingVerificationRequest(otherUserId, transactionId)
if (existingRequest != null) {
// we need to send a ready event, with matching methods
- val transport = sasTransportRoomMessageFactory.createTransport(credentials.userId, credentials.deviceId
- ?: "", roomId, null)
- val methods = existingRequest.requestInfo?.methods?.intersect(listOf(KeyVerificationStart.VERIF_METHOD_SAS))?.toList()
+ val transport = sasTransportRoomMessageFactory.createTransport(roomId, null)
+ val methods = existingRequest.requestInfo?.methods?.intersect(supportedVerificationMethods)?.toList()
if (methods.isNullOrEmpty()) {
Timber.i("Cannot ready this request, no common methods found txId:$transactionId")
// TODO buttons should not be shown in this case?
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt
index c416bd3be3..0ac3847a53 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt
@@ -16,27 +16,38 @@
package im.vector.matrix.android.internal.crypto.verification
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
+import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
+import im.vector.matrix.android.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
+import im.vector.matrix.android.internal.crypto.model.rest.VERIFICATION_METHOD_SCAN
import java.util.*
/**
* Stores current pending verification requests
*/
data class PendingVerificationRequest(
- val ageLocalTs : Long,
+ val ageLocalTs: Long,
val isIncoming: Boolean = false,
- val localID: String = UUID.randomUUID().toString(),
+ val localID: String = UUID.randomUUID().toString(),
val otherUserId: String,
+ val roomId: String?,
val transactionId: String? = null,
val requestInfo: MessageVerificationRequestContent? = null,
val readyInfo: VerificationInfoReady? = null,
val cancelConclusion: CancelCode? = null,
- val isSuccessful : Boolean = false
+ val isSuccessful: Boolean = false,
+ val handledByOtherSession: Boolean = false
) {
-
val isReady: Boolean = readyInfo != null
val isSent: Boolean = transactionId != null
val isFinished: Boolean = isSuccessful || cancelConclusion != null
+
+ fun hasMethod(method: VerificationMethod): Boolean? {
+ return when (method) {
+ VerificationMethod.SAS -> readyInfo?.methods?.contains(VERIFICATION_METHOD_SAS)
+ VerificationMethod.SCAN -> readyInfo?.methods?.contains(VERIFICATION_METHOD_SCAN)
+ }
+ }
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransport.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransport.kt
index 60e0204800..12fe5c338f 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransport.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransport.kt
@@ -34,9 +34,16 @@ internal interface SasTransport {
onErrorReason: CancelCode,
onDone: (() -> Unit)?)
- fun sendVerificationRequest(localID: String, otherUserId: String, roomId: String, callback: (String?, MessageVerificationRequestContent?) -> Unit)
+ fun sendVerificationRequest(supportedMethods: List,
+ localID: String,
+ otherUserId: String,
+ roomId: String, callback:
+ (String?, MessageVerificationRequestContent?) -> Unit)
- fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDevice: String, code: CancelCode)
+ fun cancelTransaction(transactionId: String,
+ otherUserId: String,
+ otherUserDeviceId: String,
+ code: CancelCode)
fun done(transactionId: String)
/**
@@ -58,7 +65,7 @@ internal interface SasTransport {
keyAgreementProtocols: List,
hashes: List,
messageAuthenticationCodes: List,
- shortAuthenticationStrings: List) : VerificationInfoStart
+ shortAuthenticationStrings: List): VerificationInfoStart
fun createMac(tid: String, mac: Map, keys: String): VerificationInfoMac
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportRoomMessage.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportRoomMessage.kt
index 20c59def18..c9799cc58d 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportRoomMessage.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportRoomMessage.kt
@@ -15,7 +15,6 @@
*/
package im.vector.matrix.android.internal.crypto.verification
-import android.content.Context
import androidx.lifecycle.Observer
import androidx.work.*
import com.zhuinden.monarchy.Monarchy
@@ -25,9 +24,12 @@ import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
import im.vector.matrix.android.api.session.events.model.*
import im.vector.matrix.android.api.session.room.model.message.*
import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultContent
-import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
+import im.vector.matrix.android.internal.di.DeviceId
+import im.vector.matrix.android.internal.di.SessionId
+import im.vector.matrix.android.internal.di.UserId
+import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
-import im.vector.matrix.android.internal.worker.WorkManagerUtil
+import im.vector.matrix.android.internal.util.StringProvider
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@@ -38,9 +40,11 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal class SasTransportRoomMessage(
- private val context: Context,
+ private val workManagerProvider: WorkManagerProvider,
+ private val stringProvider: StringProvider,
+ private val sessionId: String,
private val userId: String,
- private val userDevice: String,
+ private val userDeviceId: String?,
private val roomId: String,
private val monarchy: Monarchy,
private val localEchoEventFactory: LocalEchoEventFactory,
@@ -61,7 +65,7 @@ internal class SasTransportRoomMessage(
)
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
- userId = userId,
+ sessionId = sessionId,
event = event
))
val enqueueInfo = enqueueSendWork(workerParams)
@@ -84,7 +88,8 @@ internal class SasTransportRoomMessage(
// }
// }, listenerExecutor)
- val workLiveData = WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
+ val workLiveData = workManagerProvider.workManager
+ .getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
val observer = object : Observer> {
override fun onChanged(workInfoList: List?) {
@@ -113,13 +118,16 @@ internal class SasTransportRoomMessage(
}
}
- override fun sendVerificationRequest(localID: String, otherUserId: String, roomId: String,
+ override fun sendVerificationRequest(supportedMethods: List,
+ localID: String,
+ otherUserId: String,
+ roomId: String,
callback: (String?, MessageVerificationRequestContent?) -> Unit) {
val info = MessageVerificationRequestContent(
- body = context.getString(R.string.key_verification_request_fallback_message, userId),
- fromDevice = userDevice,
+ body = stringProvider.getString(R.string.key_verification_request_fallback_message, userId),
+ fromDevice = userDeviceId ?: "",
toUserId = otherUserId,
- methods = listOf(KeyVerificationStart.VERIF_METHOD_SAS)
+ methods = supportedMethods
)
val content = info.toContent()
@@ -131,24 +139,25 @@ internal class SasTransportRoomMessage(
)
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
- userId = userId,
+ sessionId = sessionId,
event = event
))
- val workRequest = WorkManagerUtil.matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.setInputData(workerParams)
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
.build()
- WorkManager.getInstance(context)
+ workManagerProvider.workManager
.beginUniqueWork("${roomId}_VerificationWork", ExistingWorkPolicy.APPEND, workRequest)
.enqueue()
// I cannot just listen to the given work request, because when used in a uniqueWork,
// The callback is called while it is still Running ...
- val workLiveData = WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
+ val workLiveData = workManagerProvider.workManager
+ .getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
val observer = object : Observer> {
override fun onChanged(workInfoList: List?) {
@@ -174,7 +183,7 @@ internal class SasTransportRoomMessage(
}
}
- override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDevice: String, code: CancelCode) {
+ override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceId: String, code: CancelCode) {
Timber.d("## SAS canceling transaction $transactionId for reason $code")
val event = createEventAndLocalEcho(
type = EventType.KEY_VERIFICATION_CANCEL,
@@ -182,7 +191,7 @@ internal class SasTransportRoomMessage(
content = MessageVerificationCancelContent.create(transactionId, code).toContent()
)
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
- userId = this.userId,
+ sessionId = sessionId,
event = event
))
enqueueSendWork(workerParams)
@@ -200,19 +209,19 @@ internal class SasTransportRoomMessage(
).toContent()
)
val workerParams = WorkerParamsFactory.toData(SendVerificationMessageWorker.Params(
- userId = userId,
+ sessionId = sessionId,
event = event
))
enqueueSendWork(workerParams)
}
private fun enqueueSendWork(workerParams: Data): Pair {
- val workRequest = WorkManagerUtil.matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.setInputData(workerParams)
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
.build()
- return WorkManager.getInstance(context)
+ return workManagerProvider.workManager
.beginUniqueWork("${roomId}_VerificationWork", ExistingWorkPolicy.APPEND, workRequest)
.enqueue() to workRequest.id
}
@@ -284,12 +293,18 @@ internal class SasTransportRoomMessage(
}
internal class SasTransportRoomMessageFactory @Inject constructor(
- private val context: Context,
+ private val workManagerProvider: WorkManagerProvider,
+ private val stringProvider: StringProvider,
private val monarchy: Monarchy,
+ @SessionId
+ private val sessionId: String,
+ @UserId
+ private val userId: String,
+ @DeviceId
+ private val deviceId: String?,
private val localEchoEventFactory: LocalEchoEventFactory) {
- fun createTransport(userId: String, userDevice: String, roomId: String, tx: SASVerificationTransaction?
- ): SasTransportRoomMessage {
- return SasTransportRoomMessage(context, userId, userDevice, roomId, monarchy, localEchoEventFactory, tx)
+ fun createTransport(roomId: String, tx: SASVerificationTransaction?): SasTransportRoomMessage {
+ return SasTransportRoomMessage(workManagerProvider, stringProvider, sessionId, userId, deviceId, roomId, monarchy, localEchoEventFactory, tx)
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportToDevice.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportToDevice.kt
index 8d73695f4a..8d280f50d8 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportToDevice.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SasTransportToDevice.kt
@@ -34,7 +34,10 @@ internal class SasTransportToDevice(
private var taskExecutor: TaskExecutor
) : SasTransport {
- override fun sendVerificationRequest(localID: String, otherUserId: String, roomId: String,
+ override fun sendVerificationRequest(supportedMethods: List,
+ localID: String,
+ otherUserId: String,
+ roomId: String,
callback: (String?, MessageVerificationRequestContent?) -> Unit) {
// TODO "not implemented"
}
@@ -78,11 +81,11 @@ internal class SasTransportToDevice(
// To device do not do anything here
}
- override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDevice: String, code: CancelCode) {
+ override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceId: String, code: CancelCode) {
Timber.d("## SAS canceling transaction $transactionId for reason $code")
val cancelMessage = KeyVerificationCancel.create(transactionId, code)
val contentMap = MXUsersDevicesMap()
- contentMap.setObject(otherUserId, otherUserDevice, cancelMessage)
+ contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage)
sendToDeviceTask
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId)) {
this.callback = object : MatrixCallback {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SendVerificationMessageWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SendVerificationMessageWorker.kt
index 55f57d80d3..47eceb179b 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SendVerificationMessageWorker.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SendVerificationMessageWorker.kt
@@ -24,6 +24,7 @@ import im.vector.matrix.android.api.failure.shouldBeRetried
import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.crypto.tasks.SendVerificationMessageTask
+import im.vector.matrix.android.internal.worker.SessionWorkerParams
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.getSessionComponent
import timber.log.Timber
@@ -34,9 +35,10 @@ internal class SendVerificationMessageWorker constructor(context: Context, param
@JsonClass(generateAdapter = true)
internal data class Params(
- val userId: String,
- val event: Event
- )
+ override val sessionId: String,
+ val event: Event,
+ override val lastFailureMessage: String? = null
+ ) : SessionWorkerParams
@Inject
lateinit var sendVerificationMessageTask: SendVerificationMessageTask
@@ -49,10 +51,10 @@ internal class SendVerificationMessageWorker constructor(context: Context, param
val params = WorkerParamsFactory.fromData(inputData)
?: return Result.success(errorOutputData)
- val sessionComponent = getSessionComponent(params.userId)
+ val sessionComponent = getSessionComponent(params.sessionId)
?: return Result.success(errorOutputData).also {
// TODO, can this happen? should I update local echo?
- Timber.e("Unknown Session, cannot send message, userId:${params.userId}")
+ Timber.e("Unknown Session, cannot send message, sessionId: ${params.sessionId}")
}
sessionComponent.inject(this)
val localId = params.event.eventId ?: ""
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt
index b084ba012d..a0a36d9982 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/StringQualifiers.kt
@@ -26,7 +26,7 @@ import javax.inject.Qualifier
internal annotation class UserId
/**
- * Used to inject the userId
+ * Used to inject the deviceId
*/
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/WorkManagerProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/WorkManagerProvider.kt
new file mode 100644
index 0000000000..82091be697
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/WorkManagerProvider.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.di
+
+import android.content.Context
+import androidx.work.*
+import javax.inject.Inject
+
+internal class WorkManagerProvider @Inject constructor(
+ context: Context,
+ @SessionId private val sessionId: String
+) {
+ private val tag = MATRIX_SDK_TAG_PREFIX + sessionId
+
+ val workManager = WorkManager.getInstance(context)
+
+ /**
+ * Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag
+ */
+ inline fun matrixOneTimeWorkRequestBuilder() =
+ OneTimeWorkRequestBuilder()
+ .addTag(tag)
+
+ /**
+ * Cancel all works instantiated by the Matrix SDK for the current session, and not those from the SDK client, or for other sessions
+ */
+ fun cancelAllWorks() {
+ workManager.let {
+ it.cancelAllWorkByTag(tag)
+ it.pruneWork()
+ }
+ }
+
+ companion object {
+ private const val MATRIX_SDK_TAG_PREFIX = "MatrixSDK-"
+
+ /**
+ * Default constraints: connected network
+ */
+ val workConstraints = Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build()
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt
index e22e47bc1c..537bc63355 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt
@@ -16,7 +16,6 @@
package im.vector.matrix.android.internal.session
-import android.content.Context
import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import dagger.Lazy
@@ -46,6 +45,7 @@ import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.di.SessionId
+import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.sync.SyncTaskSequencer
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
import im.vector.matrix.android.internal.session.sync.job.SyncThread
@@ -63,7 +63,7 @@ import javax.inject.Provider
@SessionScope
internal class DefaultSession @Inject constructor(
override val sessionParams: SessionParams,
- private val context: Context,
+ private val workManagerProvider: WorkManagerProvider,
private val eventBus: EventBus,
@SessionId
override val sessionId: String,
@@ -122,15 +122,15 @@ internal class DefaultSession @Inject constructor(
}
override fun requireBackgroundSync() {
- SyncWorker.requireBackgroundSync(context, sessionId)
+ SyncWorker.requireBackgroundSync(workManagerProvider, sessionId)
}
override fun startAutomaticBackgroundSync(repeatDelay: Long) {
- SyncWorker.automaticallyBackgroundSync(context, sessionId, 0, repeatDelay)
+ SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, 0, repeatDelay)
}
override fun stopAnyBackgroundSync() {
- SyncWorker.stopAnyBackgroundSync(context)
+ SyncWorker.stopAnyBackgroundSync(workManagerProvider)
}
override fun startSync(fromForeground: Boolean) {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt
index a60bc78b6c..3ca5a03822 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt
@@ -16,9 +16,7 @@
package im.vector.matrix.android.internal.session.group
-import android.content.Context
import androidx.work.ExistingWorkPolicy
-import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
@@ -27,8 +25,7 @@ import im.vector.matrix.android.internal.database.model.GroupEntity
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionId
-import im.vector.matrix.android.internal.worker.WorkManagerUtil
-import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
+import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import io.realm.OrderedCollectionChangeSet
import io.realm.RealmResults
@@ -38,7 +35,7 @@ import javax.inject.Inject
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
internal class GroupSummaryUpdater @Inject constructor(
- private val context: Context,
+ private val workManagerProvider: WorkManagerProvider,
@SessionId private val sessionId: String,
private val monarchy: Monarchy)
: RealmLiveEntityObserver(monarchy.realmConfiguration) {
@@ -72,12 +69,12 @@ internal class GroupSummaryUpdater @Inject constructor(
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)
- val sendWork = matrixOneTimeWorkRequestBuilder()
+ val sendWork = workManagerProvider.matrixOneTimeWorkRequestBuilder()
.setInputData(workData)
- .setConstraints(WorkManagerUtil.workConstraints)
+ .setConstraints(WorkManagerProvider.workConstraints)
.build()
- WorkManager.getInstance(context)
+ workManagerProvider.workManager
.beginUniqueWork(GET_GROUP_DATA_WORKER, ExistingWorkPolicy.APPEND, sendWork)
.enqueue()
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt
index cdbf6aeee4..9d80223149 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/DefaultPusherService.kt
@@ -15,10 +15,8 @@
*/
package im.vector.matrix.android.internal.session.pushers
-import android.content.Context
import androidx.lifecycle.LiveData
import androidx.work.BackoffPolicy
-import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.pushers.Pusher
@@ -27,17 +25,16 @@ import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionId
+import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
-import im.vector.matrix.android.internal.worker.WorkManagerUtil
-import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal class DefaultPusherService @Inject constructor(
- private val context: Context,
+ private val workManagerProvider: WorkManagerProvider,
private val monarchy: Monarchy,
@SessionId private val sessionId: String,
private val getPusherTask: GetPushersTask,
@@ -68,12 +65,12 @@ internal class DefaultPusherService @Inject constructor(
val params = AddHttpPusherWorker.Params(sessionId, pusher)
- val request = matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ val request = workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.setInputData(WorkerParamsFactory.toData(params))
.setBackoffCriteria(BackoffPolicy.LINEAR, 10_000L, TimeUnit.MILLISECONDS)
.build()
- WorkManager.getInstance(context).enqueue(request)
+ workManagerProvider.workManager.enqueue(request)
return request.id
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt
index 1b2b27a3eb..8039a4cd5d 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt
@@ -15,7 +15,6 @@
*/
package im.vector.matrix.android.internal.session.room.relation
-import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import androidx.work.OneTimeWorkRequest
@@ -46,15 +45,14 @@ import im.vector.matrix.android.internal.session.room.send.SendEventWorker
import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
-import im.vector.matrix.android.internal.util.CancelableWork
import im.vector.matrix.android.internal.util.fetchCopyMap
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import timber.log.Timber
internal class DefaultRelationService @AssistedInject constructor(
@Assisted private val roomId: String,
- private val context: Context,
@SessionId private val sessionId: String,
+ private val timeLineSendEventWorkCommon: TimelineSendEventWorkCommon,
private val eventFactory: LocalEchoEventFactory,
private val cryptoService: CryptoService,
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
@@ -85,8 +83,7 @@ internal class DefaultRelationService @AssistedInject constructor(
val event = eventFactory.createReactionEvent(roomId, targetEventId, reaction)
.also { saveLocalEcho(it) }
val sendRelationWork = createSendEventWork(event, true)
- TimelineSendEventWorkCommon.postWork(context, roomId, sendRelationWork)
- CancelableWork(context, sendRelationWork.id)
+ timeLineSendEventWorkCommon.postWork(roomId, sendRelationWork)
} else {
Timber.w("Reaction already added")
NoOpCancellable
@@ -111,7 +108,7 @@ internal class DefaultRelationService @AssistedInject constructor(
.also { saveLocalEcho(it) }
val redactWork = createRedactEventWork(redactEvent, toRedact, null)
- TimelineSendEventWorkCommon.postWork(context, roomId, redactWork)
+ timeLineSendEventWorkCommon.postWork(roomId, redactWork)
}
}
}
@@ -132,7 +129,7 @@ internal class DefaultRelationService @AssistedInject constructor(
eventId,
reason)
val redactWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
- return TimelineSendEventWorkCommon.createWork(redactWorkData, true)
+ return timeLineSendEventWorkCommon.createWork(redactWorkData, true)
}
override fun editTextMessage(targetEventId: String,
@@ -146,12 +143,10 @@ internal class DefaultRelationService @AssistedInject constructor(
return if (cryptoService.isRoomEncrypted(roomId)) {
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
val workRequest = createSendEventWork(event, false)
- TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
- CancelableWork(context, encryptWork.id)
+ timeLineSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, workRequest)
} else {
val workRequest = createSendEventWork(event, true)
- TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
- CancelableWork(context, workRequest.id)
+ timeLineSendEventWorkCommon.postWork(roomId, workRequest)
}
}
@@ -168,12 +163,10 @@ internal class DefaultRelationService @AssistedInject constructor(
return if (cryptoService.isRoomEncrypted(roomId)) {
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
val workRequest = createSendEventWork(event, false)
- TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
- CancelableWork(context, encryptWork.id)
+ timeLineSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, workRequest)
} else {
val workRequest = createSendEventWork(event, true)
- TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
- CancelableWork(context, workRequest.id)
+ timeLineSendEventWorkCommon.postWork(roomId, workRequest)
}
}
@@ -194,12 +187,10 @@ internal class DefaultRelationService @AssistedInject constructor(
return if (cryptoService.isRoomEncrypted(roomId)) {
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
val workRequest = createSendEventWork(event, false)
- TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
- CancelableWork(context, encryptWork.id)
+ timeLineSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, workRequest)
} else {
val workRequest = createSendEventWork(event, true)
- TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
- CancelableWork(context, workRequest.id)
+ timeLineSendEventWorkCommon.postWork(roomId, workRequest)
}
}
@@ -207,13 +198,13 @@ internal class DefaultRelationService @AssistedInject constructor(
// Same parameter
val params = EncryptEventWorker.Params(sessionId, roomId, event, keepKeys)
val sendWorkData = WorkerParamsFactory.toData(params)
- return TimelineSendEventWorkCommon.createWork(sendWorkData, true)
+ return timeLineSendEventWorkCommon.createWork(sendWorkData, true)
}
private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest {
val sendContentWorkerParams = SendEventWorker.Params(sessionId, roomId, event)
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
- return TimelineSendEventWorkCommon.createWork(sendWorkData, startChain)
+ return timeLineSendEventWorkCommon.createWork(sendWorkData, startChain)
}
override fun getEventAnnotationsSummary(eventId: String): EventAnnotationsSummary? {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt
index 9942e36593..121436a9bf 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/DefaultSendService.kt
@@ -16,8 +16,10 @@
package im.vector.matrix.android.internal.session.room.send
-import android.content.Context
-import androidx.work.*
+import androidx.work.BackoffPolicy
+import androidx.work.ExistingWorkPolicy
+import androidx.work.OneTimeWorkRequest
+import androidx.work.Operation
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import com.zhuinden.monarchy.Monarchy
@@ -38,12 +40,11 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionId
+import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.content.UploadContentWorker
import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon
import im.vector.matrix.android.internal.util.CancelableWork
import im.vector.matrix.android.internal.worker.AlwaysSuccessfulWorker
-import im.vector.matrix.android.internal.worker.WorkManagerUtil
-import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.startChain
import timber.log.Timber
@@ -55,7 +56,8 @@ private const val BACKOFF_DELAY = 10_000L
internal class DefaultSendService @AssistedInject constructor(
@Assisted private val roomId: String,
- private val context: Context,
+ private val workManagerProvider: WorkManagerProvider,
+ private val timelineSendEventWorkCommon: TimelineSendEventWorkCommon,
@SessionId private val sessionId: String,
private val localEchoEventFactory: LocalEchoEventFactory,
private val cryptoService: CryptoService,
@@ -91,12 +93,10 @@ internal class DefaultSendService @AssistedInject constructor(
Timber.v("Send event in encrypted room")
val encryptWork = createEncryptEventWork(event, true)
val sendWork = createSendEventWork(event, false)
- TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, sendWork)
- CancelableWork(context, encryptWork.id)
+ timelineSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, sendWork)
} else {
val sendWork = createSendEventWork(event, true)
- TimelineSendEventWorkCommon.postWork(context, roomId, sendWork)
- CancelableWork(context, sendWork.id)
+ timelineSendEventWorkCommon.postWork(roomId, sendWork)
}
}
@@ -109,8 +109,7 @@ internal class DefaultSendService @AssistedInject constructor(
override fun redactEvent(event: Event, reason: String?): Cancelable {
// TODO manage media/attachements?
val redactWork = createRedactEventWork(event, reason)
- TimelineSendEventWorkCommon.postWork(context, roomId, redactWork)
- return CancelableWork(context, redactWork.id)
+ return timelineSendEventWorkCommon.postWork(roomId, redactWork)
}
override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? {
@@ -168,16 +167,16 @@ internal class DefaultSendService @AssistedInject constructor(
}
override fun clearSendingQueue() {
- TimelineSendEventWorkCommon.cancelAllWorks(context, roomId)
- WorkManager.getInstance(context).cancelUniqueWork(buildWorkName(UPLOAD_WORK))
+ timelineSendEventWorkCommon.cancelAllWorks(roomId)
+ workManagerProvider.workManager.cancelUniqueWork(buildWorkName(UPLOAD_WORK))
// Replace the worker chains with a AlwaysSuccessfulWorker, to ensure the queues are well emptied
- matrixOneTimeWorkRequestBuilder()
+ workManagerProvider.matrixOneTimeWorkRequestBuilder()
.build().let {
- TimelineSendEventWorkCommon.postWork(context, roomId, it, ExistingWorkPolicy.REPLACE)
+ timelineSendEventWorkCommon.postWork(roomId, it, ExistingWorkPolicy.REPLACE)
// need to clear also image sending queue
- WorkManager.getInstance(context)
+ workManagerProvider.workManager
.beginUniqueWork(buildWorkName(UPLOAD_WORK), ExistingWorkPolicy.REPLACE, it)
.enqueue()
}
@@ -245,7 +244,7 @@ internal class DefaultSendService @AssistedInject constructor(
return internalSendMedia(event, attachment)
}
- private fun internalSendMedia(localEcho: Event, attachment: ContentAttachmentData): CancelableWork {
+ private fun internalSendMedia(localEcho: Event, attachment: ContentAttachmentData): Cancelable {
val isRoomEncrypted = cryptoService.isRoomEncrypted(roomId)
val uploadWork = createUploadMediaWork(localEcho, attachment, isRoomEncrypted, startChain = true)
@@ -254,7 +253,7 @@ internal class DefaultSendService @AssistedInject constructor(
if (isRoomEncrypted) {
val encryptWork = createEncryptEventWork(localEcho, false /*not start of chain, take input error*/)
- val op: Operation = WorkManager.getInstance(context)
+ val op: Operation = workManagerProvider.workManager
.beginUniqueWork(buildWorkName(UPLOAD_WORK), ExistingWorkPolicy.APPEND, uploadWork)
.then(encryptWork)
.then(sendWork)
@@ -267,13 +266,13 @@ internal class DefaultSendService @AssistedInject constructor(
}
}, workerFutureListenerExecutor)
} else {
- WorkManager.getInstance(context)
+ workManagerProvider.workManager
.beginUniqueWork(buildWorkName(UPLOAD_WORK), ExistingWorkPolicy.APPEND, uploadWork)
.then(sendWork)
.enqueue()
}
- return CancelableWork(context, sendWork.id)
+ return CancelableWork(workManagerProvider.workManager, sendWork.id)
}
private fun saveLocalEcho(event: Event) {
@@ -289,8 +288,8 @@ internal class DefaultSendService @AssistedInject constructor(
val params = EncryptEventWorker.Params(sessionId, roomId, event)
val sendWorkData = WorkerParamsFactory.toData(params)
- return matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ return workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.setInputData(sendWorkData)
.startChain(startChain)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
@@ -301,7 +300,7 @@ internal class DefaultSendService @AssistedInject constructor(
val sendContentWorkerParams = SendEventWorker.Params(sessionId, roomId, event)
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
- return TimelineSendEventWorkCommon.createWork(sendWorkData, startChain)
+ return timelineSendEventWorkCommon.createWork(sendWorkData, startChain)
}
private fun createRedactEventWork(event: Event, reason: String?): OneTimeWorkRequest {
@@ -310,7 +309,7 @@ internal class DefaultSendService @AssistedInject constructor(
}
val sendContentWorkerParams = RedactEventWorker.Params(sessionId, redactEvent.eventId!!, roomId, event.eventId, reason)
val redactWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
- return TimelineSendEventWorkCommon.createWork(redactWorkData, true)
+ return timelineSendEventWorkCommon.createWork(redactWorkData, true)
}
private fun createUploadMediaWork(event: Event,
@@ -320,8 +319,8 @@ internal class DefaultSendService @AssistedInject constructor(
val uploadMediaWorkerParams = UploadContentWorker.Params(sessionId, roomId, event, attachment, isRoomEncrypted)
val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams)
- return matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ return workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.startChain(startChain)
.setInputData(uploadWorkData)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt
index f6f894d860..ff3cedf044 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineSendEventWorkCommon.kt
@@ -15,51 +15,54 @@
*/
package im.vector.matrix.android.internal.session.room.timeline
-import android.content.Context
import androidx.work.*
-import im.vector.matrix.android.internal.worker.WorkManagerUtil
-import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
+import im.vector.matrix.android.api.util.Cancelable
+import im.vector.matrix.android.api.util.NoOpCancellable
+import im.vector.matrix.android.internal.di.WorkManagerProvider
+import im.vector.matrix.android.internal.util.CancelableWork
import im.vector.matrix.android.internal.worker.startChain
import java.util.concurrent.TimeUnit
-
-private const val SEND_WORK = "SEND_WORK"
-private const val BACKOFF_DELAY = 10_000L
+import javax.inject.Inject
/**
* Helper class for sending event related works.
* All send event from a room are using the same workchain, in order to ensure order.
- * WorkRequest must always return success (even if server error, in this case marking the event as failed to send)
- * , if not the chain will be doomed in failed state.
- *
+ * WorkRequest must always return success (even if server error, in this case marking the event as failed to send),
+ * if not the chain will be doomed in failed state.
*/
-internal object TimelineSendEventWorkCommon {
+internal class TimelineSendEventWorkCommon @Inject constructor(
+ private val workManagerProvider: WorkManagerProvider
+) {
- fun postSequentialWorks(context: Context, roomId: String, vararg workRequests: OneTimeWorkRequest) {
- when {
- workRequests.isEmpty() -> return
- workRequests.size == 1 -> postWork(context, roomId, workRequests.first())
+ fun postSequentialWorks(roomId: String, vararg workRequests: OneTimeWorkRequest): Cancelable {
+ return when {
+ workRequests.isEmpty() -> NoOpCancellable
+ workRequests.size == 1 -> postWork(roomId, workRequests.first())
else -> {
val firstWork = workRequests.first()
- var continuation = WorkManager.getInstance(context)
+ var continuation = workManagerProvider.workManager
.beginUniqueWork(buildWorkName(roomId), ExistingWorkPolicy.APPEND, firstWork)
for (i in 1 until workRequests.size) {
val workRequest = workRequests[i]
continuation = continuation.then(workRequest)
}
continuation.enqueue()
+ CancelableWork(workManagerProvider.workManager, firstWork.id)
}
}
}
- fun postWork(context: Context, roomId: String, workRequest: OneTimeWorkRequest, policy: ExistingWorkPolicy = ExistingWorkPolicy.APPEND) {
- WorkManager.getInstance(context)
+ fun postWork(roomId: String, workRequest: OneTimeWorkRequest, policy: ExistingWorkPolicy = ExistingWorkPolicy.APPEND): Cancelable {
+ workManagerProvider.workManager
.beginUniqueWork(buildWorkName(roomId), policy, workRequest)
.enqueue()
+
+ return CancelableWork(workManagerProvider.workManager, workRequest.id)
}
inline fun createWork(data: Data, startChain: Boolean): OneTimeWorkRequest {
- return matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ return workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.startChain(startChain)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
@@ -70,7 +73,13 @@ internal object TimelineSendEventWorkCommon {
return "${roomId}_$SEND_WORK"
}
- fun cancelAllWorks(context: Context, roomId: String) {
- WorkManager.getInstance(context).cancelUniqueWork(buildWorkName(roomId))
+ fun cancelAllWorks(roomId: String) {
+ workManagerProvider.workManager
+ .cancelUniqueWork(buildWorkName(roomId))
+ }
+
+ companion object {
+ private const val SEND_WORK = "SEND_WORK"
+ private const val BACKOFF_DELAY = 10_000L
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt
index e6913f8b54..05a2324047 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt
@@ -16,7 +16,6 @@
package im.vector.matrix.android.internal.session.signout
-import android.content.Context
import im.vector.matrix.android.BuildConfig
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError
@@ -29,7 +28,6 @@ import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.SessionModule
import im.vector.matrix.android.internal.session.cache.ClearCacheTask
import im.vector.matrix.android.internal.task.Task
-import im.vector.matrix.android.internal.worker.WorkManagerUtil
import io.realm.Realm
import io.realm.RealmConfiguration
import org.greenrobot.eventbus.EventBus
@@ -45,7 +43,7 @@ internal interface SignOutTask : Task {
}
internal class DefaultSignOutTask @Inject constructor(
- private val context: Context,
+ private val workManagerProvider: WorkManagerProvider,
@SessionId private val sessionId: String,
private val signOutAPI: SignOutAPI,
private val sessionManager: SessionManager,
@@ -87,7 +85,7 @@ internal class DefaultSignOutTask @Inject constructor(
sessionManager.releaseSession(sessionId)
Timber.d("SignOut: cancel pending works...")
- WorkManagerUtil.cancelAllWorks(context)
+ workManagerProvider.cancelAllWorks()
Timber.d("SignOut: delete session params...")
sessionParamsStore.delete(sessionId)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt
index 3637cc624f..c844db8d33 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt
@@ -16,15 +16,17 @@
package im.vector.matrix.android.internal.session.sync.job
import android.content.Context
-import androidx.work.*
+import androidx.work.BackoffPolicy
+import androidx.work.CoroutineWorker
+import androidx.work.ExistingWorkPolicy
+import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.failure.isTokenError
+import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
import im.vector.matrix.android.internal.session.sync.SyncTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.worker.SessionWorkerParams
-import im.vector.matrix.android.internal.worker.WorkManagerUtil
-import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.getSessionComponent
import timber.log.Timber
@@ -75,30 +77,33 @@ internal class SyncWorker(context: Context,
companion object {
- const val BG_SYNC_WORK_NAME = "BG_SYNCP"
+ private const val BG_SYNC_WORK_NAME = "BG_SYNCP"
- fun requireBackgroundSync(context: Context, sessionId: String, serverTimeout: Long = 0) {
+ fun requireBackgroundSync(workManagerProvider: WorkManagerProvider, sessionId: String, serverTimeout: Long = 0) {
val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, false))
- val workRequest = matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS)
.setInputData(data)
.build()
- WorkManager.getInstance(context).enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
+ workManagerProvider.workManager
+ .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
}
- fun automaticallyBackgroundSync(context: Context, sessionId: String, serverTimeout: Long = 0, delay: Long = 30_000) {
+ fun automaticallyBackgroundSync(workManagerProvider: WorkManagerProvider, sessionId: String, serverTimeout: Long = 0, delay: Long = 30_000) {
val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, true))
- val workRequest = matrixOneTimeWorkRequestBuilder()
- .setConstraints(WorkManagerUtil.workConstraints)
+ val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder()
+ .setConstraints(WorkManagerProvider.workConstraints)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, delay, TimeUnit.MILLISECONDS)
.build()
- WorkManager.getInstance(context).enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
+ workManagerProvider.workManager
+ .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
}
- fun stopAnyBackgroundSync(context: Context) {
- WorkManager.getInstance(context).cancelUniqueWork(BG_SYNC_WORK_NAME)
+ fun stopAnyBackgroundSync(workManagerProvider: WorkManagerProvider) {
+ workManagerProvider.workManager
+ .cancelUniqueWork(BG_SYNC_WORK_NAME)
}
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt
index bff20a80e7..cba104ebe8 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CancelableWork.kt
@@ -16,15 +16,14 @@
package im.vector.matrix.android.internal.util
-import android.content.Context
import androidx.work.WorkManager
import im.vector.matrix.android.api.util.Cancelable
-import java.util.UUID
+import java.util.*
-internal class CancelableWork(private val context: Context,
+internal class CancelableWork(private val workManager: WorkManager,
private val workId: UUID) : Cancelable {
override fun cancel() {
- WorkManager.getInstance(context).cancelWorkById(workId)
+ workManager.cancelWorkById(workId)
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkManagerUtil.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkManagerUtil.kt
deleted file mode 100644
index 27ec28dcac..0000000000
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/worker/WorkManagerUtil.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.matrix.android.internal.worker
-
-import android.content.Context
-import androidx.work.*
-
-// TODO Multiaccount
-internal object WorkManagerUtil {
- private const val MATRIX_SDK_TAG = "MatrixSDK"
-
- /**
- * Default constraints: connected network
- */
- val workConstraints = Constraints.Builder()
- .setRequiredNetworkType(NetworkType.CONNECTED)
- .build()
-
- /**
- * Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag
- */
- inline fun matrixOneTimeWorkRequestBuilder() =
- OneTimeWorkRequestBuilder()
- .addTag(MATRIX_SDK_TAG)
-
- /**
- * Cancel all works instantiated by the Matrix SDK and not those from the SDK client
- */
- fun cancelAllWorks(context: Context) {
- WorkManager.getInstance(context).also {
- it.cancelAllWorkByTag(MATRIX_SDK_TAG)
- it.pruneWork()
- }
- }
-}
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index a0d4402767..c6e4b51c44 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -47,9 +47,6 @@
android:label="@string/title_activity_settings"
android:windowSoftInputMode="adjustResize" />
-
diff --git a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt
index 6855631aa3..53bd7d169f 100644
--- a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt
+++ b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt
@@ -23,7 +23,10 @@ import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupSettingsFragment
-import im.vector.riotx.features.crypto.verification.*
+import im.vector.riotx.features.crypto.verification.choose.VerificationChooseMethodFragment
+import im.vector.riotx.features.crypto.verification.conclusion.VerificationConclusionFragment
+import im.vector.riotx.features.crypto.verification.emoji.VerificationEmojiCodeFragment
+import im.vector.riotx.features.crypto.verification.request.VerificationRequestFragment
import im.vector.riotx.features.home.HomeDetailFragment
import im.vector.riotx.features.home.HomeDrawerFragment
import im.vector.riotx.features.home.LoadingFragment
@@ -239,26 +242,6 @@ interface FragmentModule {
@FragmentKey(VectorSettingsDevicesFragment::class)
fun bindVectorSettingsDevicesFragment(fragment: VectorSettingsDevicesFragment): Fragment
- @Binds
- @IntoMap
- @FragmentKey(SASVerificationIncomingFragment::class)
- fun bindSASVerificationIncomingFragment(fragment: SASVerificationIncomingFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SASVerificationShortCodeFragment::class)
- fun bindSASVerificationShortCodeFragment(fragment: SASVerificationShortCodeFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SASVerificationVerifiedFragment::class)
- fun bindSASVerificationVerifiedFragment(fragment: SASVerificationVerifiedFragment): Fragment
-
- @Binds
- @IntoMap
- @FragmentKey(SASVerificationStartFragment::class)
- fun bindSASVerificationStartFragment(fragment: SASVerificationStartFragment): Fragment
-
@Binds
@IntoMap
@FragmentKey(PublicRoomsFragment::class)
@@ -302,15 +285,15 @@ interface FragmentModule {
@Binds
@IntoMap
@FragmentKey(VerificationChooseMethodFragment::class)
- fun bindVerificationMethodChooserFragment(fragment: VerificationChooseMethodFragment): Fragment
+ fun bindVerificationChooseMethodFragment(fragment: VerificationChooseMethodFragment): Fragment
@Binds
@IntoMap
- @FragmentKey(SASVerificationCodeFragment::class)
- fun bindVerificationSasCodeFragment(fragment: SASVerificationCodeFragment): Fragment
+ @FragmentKey(VerificationEmojiCodeFragment::class)
+ fun bindVerificationEmojiCodeFragment(fragment: VerificationEmojiCodeFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VerificationConclusionFragment::class)
- fun bindVerificationSasConclusionFragment(fragment: VerificationConclusionFragment): Fragment
+ fun bindVerificationConclusionFragment(fragment: VerificationConclusionFragment): Fragment
}
diff --git a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt
index 5d4288f4b8..4bb0adb9f0 100644
--- a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt
+++ b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt
@@ -27,7 +27,6 @@ import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreFromK
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreFromPassphraseViewModel
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreSharedViewModel
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupSharedViewModel
-import im.vector.riotx.features.crypto.verification.SasVerificationViewModel
import im.vector.riotx.features.home.HomeSharedActionViewModel
import im.vector.riotx.features.home.room.detail.RoomDetailSharedActionViewModel
import im.vector.riotx.features.home.room.detail.timeline.action.MessageSharedActionViewModel
@@ -61,11 +60,6 @@ interface ViewModelModule {
@ViewModelKey(EmojiChooserViewModel::class)
fun bindEmojiChooserViewModel(viewModel: EmojiChooserViewModel): ViewModel
- @Binds
- @IntoMap
- @ViewModelKey(SasVerificationViewModel::class)
- fun bindSasVerificationViewModel(viewModel: SasVerificationViewModel): ViewModel
-
@Binds
@IntoMap
@ViewModelKey(KeysBackupRestoreFromKeyViewModel::class)
diff --git a/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt b/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt
index e6336e5753..25bf2f514a 100644
--- a/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt
+++ b/vector/src/main/java/im/vector/riotx/core/epoxy/ErrorWithRetryItem.kt
@@ -18,6 +18,7 @@ package im.vector.riotx.core.epoxy
import android.widget.Button
import android.widget.TextView
+import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R
@@ -33,6 +34,7 @@ abstract class ErrorWithRetryItem : VectorEpoxyModel(
override fun bind(holder: Holder) {
holder.textView.text = text
+ holder.buttonView.isVisible = listener != null
holder.buttonView.setOnClickListener { listener?.invoke() }
}
diff --git a/vector/src/main/java/im/vector/riotx/core/extensions/RecyclerView.kt b/vector/src/main/java/im/vector/riotx/core/extensions/RecyclerView.kt
index 3d247e149c..51f3ce611a 100644
--- a/vector/src/main/java/im/vector/riotx/core/extensions/RecyclerView.kt
+++ b/vector/src/main/java/im/vector/riotx/core/extensions/RecyclerView.kt
@@ -28,12 +28,17 @@ fun RecyclerView.configureWith(epoxyController: EpoxyController,
itemAnimator: RecyclerView.ItemAnimator? = null,
viewPool: RecyclerView.RecycledViewPool? = null,
showDivider: Boolean = false,
- hasFixedSize: Boolean = true) {
+ hasFixedSize: Boolean = true,
+ disableItemAnimation: Boolean = false) {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false).apply {
recycleChildrenOnDetach = viewPool != null
}
setRecycledViewPool(viewPool)
- itemAnimator?.let { this.itemAnimator = it }
+ if (disableItemAnimation) {
+ this.itemAnimator = null
+ } else {
+ itemAnimator?.let { this.itemAnimator = it }
+ }
if (showDivider) {
addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
}
diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt
index 5c73fc97da..15f541f72d 100644
--- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt
@@ -102,9 +102,11 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
private lateinit var sessionListener: SessionListener
protected lateinit var bugReporter: BugReporter
lateinit var rageShake: RageShake
+
+ lateinit var navigator: Navigator
private set
- protected lateinit var navigator: Navigator
private lateinit var fragmentFactory: FragmentFactory
+
private lateinit var activeSessionHolder: ActiveSessionHolder
private lateinit var vectorPreferences: VectorPreferences
@@ -210,8 +212,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
handleInvalidToken(globalError)
is GlobalError.ConsentNotGivenError ->
consentNotGivenHelper.displayDialog(globalError.consentUri,
- activeSessionHolder.getActiveSession().sessionParams.homeServerConnectionConfig.homeServerUri.host
- ?: "")
+ activeSessionHolder.getActiveSession().sessionParams.homeServerConnectionConfig.homeServerUri.host
+ ?: "")
}
}
diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt
index b3a56f48ee..c066ffff43 100644
--- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseBottomSheetDialogFragment.kt
@@ -19,10 +19,16 @@ import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.os.Parcelable
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.annotation.CallSuper
+import androidx.annotation.LayoutRes
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
+import butterknife.ButterKnife
+import butterknife.Unbinder
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.MvRxView
import com.airbnb.mvrx.MvRxViewId
@@ -43,6 +49,15 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
final override val mvrxViewId: String by mvrxViewIdProperty
private lateinit var screenComponent: ScreenComponent
+ /* ==========================================================================================
+ * View
+ * ========================================================================================== */
+
+ @LayoutRes
+ abstract fun getLayoutResId(): Int
+
+ private var unBinder: Unbinder? = null
+
/* ==========================================================================================
* View model
* ========================================================================================== */
@@ -67,6 +82,18 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
open val showExpanded = false
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ val view = inflater.inflate(getLayoutResId(), container, false)
+ unBinder = ButterKnife.bind(this, view)
+ return view
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ unBinder?.unbind()
+ unBinder = null
+ }
+
override fun onAttach(context: Context) {
screenComponent = DaggerScreenComponent.factory().create(vectorBaseActivity.getVectorComponent(), vectorBaseActivity)
viewModelFactory = screenComponent.viewModelFactory()
diff --git a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt
index c3a66dce1e..1fcc8d443b 100644
--- a/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/createdirect/CreateDirectRoomKnownUsersFragment.kt
@@ -98,10 +98,9 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor(
}
private fun setupRecyclerView() {
- // Don't activate animation as we might have way to much item animation when filtering
- recyclerView.itemAnimator = null
knownUsersController.callback = this
- recyclerView.configureWith(knownUsersController)
+ // Don't activate animation as we might have way to much item animation when filtering
+ recyclerView.configureWith(knownUsersController, disableItemAnimation = true)
}
private fun setupFilterView() {
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt
index f5db16c8ee..1af7d2fbd1 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt
@@ -33,13 +33,11 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.riotx.R
-import im.vector.riotx.features.crypto.verification.SASVerificationActivity
import im.vector.riotx.features.popup.PopupAlertManager
import timber.log.Timber
import java.text.DateFormat
import java.text.SimpleDateFormat
-import java.util.Locale
-import java.util.Date
+import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.collections.ArrayList
@@ -195,18 +193,19 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
denyAllRequests(mappingKey)
}
- alert.addButton(
- context.getString(R.string.start_verification_short_label),
- Runnable {
- alert.weakCurrentActivity?.get()?.let {
- val intent = SASVerificationActivity.outgoingIntent(it,
- session?.myUserId ?: "",
- userId, deviceId)
- it.startActivity(intent)
- }
- },
- false
- )
+ // TODO send to the new profile page
+// alert.addButton(
+// context.getString(R.string.start_verification_short_label),
+// Runnable {
+// alert.weakCurrentActivity?.get()?.let {
+// val intent = SASVerificationActivity.outgoingIntent(it,
+// session?.myUserId ?: "",
+// userId, deviceId)
+// it.startActivity(intent)
+// }
+// },
+// false
+// )
alert.addButton(context.getString(R.string.share_without_verifying_short_label), Runnable {
shareAllSessions(mappingKey)
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/Config.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/Config.kt
new file mode 100644
index 0000000000..0bc9a3e144
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/Config.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotx.features.crypto.verification
+
+import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
+
+// TODO Add support for SCAN (QR code)
+val supportedVerificationMethods = listOf(VerificationMethod.SAS)
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt
index 22ccec534a..b59e2d3f8c 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt
@@ -20,8 +20,13 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
+import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
import im.vector.riotx.R
+import im.vector.riotx.core.platform.VectorBaseActivity
+import im.vector.riotx.features.home.room.detail.RoomDetailActivity
+import im.vector.riotx.features.home.room.detail.RoomDetailArgs
import im.vector.riotx.features.popup.PopupAlertManager
+import im.vector.riotx.features.themes.ThemeUtils
import javax.inject.Inject
import javax.inject.Singleton
@@ -48,46 +53,46 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
override fun transactionUpdated(tx: SasVerificationTransaction) {
when (tx.state) {
SasVerificationTxState.OnStarted -> {
- // Add a notification for every incoming request
- val name = session?.getUser(tx.otherUserId)?.displayName
- ?: tx.otherUserId
-
- val alert = PopupAlertManager.VectorAlert(
- "kvr_${tx.transactionId}",
- context.getString(R.string.sas_incoming_request_notif_title),
- context.getString(R.string.sas_incoming_request_notif_content, name),
- R.drawable.shield)
- .apply {
- contentAction = Runnable {
- val intent = SASVerificationActivity.incomingIntent(context,
- session?.myUserId ?: "",
- tx.otherUserId,
- tx.transactionId)
- weakCurrentActivity?.get()?.startActivity(intent)
- }
- dismissedAction = Runnable {
- tx.cancel()
- }
- addButton(
- context.getString(R.string.ignore),
- Runnable {
- tx.cancel()
- }
- )
- addButton(
- context.getString(R.string.action_open),
- Runnable {
- val intent = SASVerificationActivity.incomingIntent(context,
- session?.myUserId ?: "",
- tx.otherUserId,
- tx.transactionId)
- weakCurrentActivity?.get()?.startActivity(intent)
- }
- )
- // 10mn expiration
- expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L)
- }
- PopupAlertManager.postVectorAlert(alert)
+// // Add a notification for every incoming request
+// val name = session?.getUser(tx.otherUserId)?.displayName
+// ?: tx.otherUserId
+//
+// val alert = PopupAlertManager.VectorAlert(
+// "kvr_${tx.transactionId}",
+// context.getString(R.string.sas_incoming_request_notif_title),
+// context.getString(R.string.sas_incoming_request_notif_content, name),
+// R.drawable.shield)
+// .apply {
+// contentAction = Runnable {
+// val intent = SASVerificationActivity.incomingIntent(context,
+// session?.myUserId ?: "",
+// tx.otherUserId,
+// tx.transactionId)
+// weakCurrentActivity?.get()?.startActivity(intent)
+// }
+// dismissedAction = Runnable {
+// tx.cancel()
+// }
+// addButton(
+// context.getString(R.string.ignore),
+// Runnable {
+// tx.cancel()
+// }
+// )
+// addButton(
+// context.getString(R.string.action_open),
+// Runnable {
+// val intent = SASVerificationActivity.incomingIntent(context,
+// session?.myUserId ?: "",
+// tx.otherUserId,
+// tx.transactionId)
+// weakCurrentActivity?.get()?.startActivity(intent)
+// }
+// )
+// // 10mn expiration
+// expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L)
+// }
+// PopupAlertManager.postVectorAlert(alert)
}
SasVerificationTxState.Cancelled,
SasVerificationTxState.OnCancelled,
@@ -101,4 +106,54 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context
override fun markedAsManuallyVerified(userId: String, deviceId: String) {
}
+
+ override fun verificationRequestCreated(pr: PendingVerificationRequest) {
+ // For incoming request we should prompt (if not in activity where this request apply)
+ if (pr.isIncoming) {
+ val name = session?.getUser(pr.otherUserId)?.displayName
+ ?: pr.otherUserId
+
+ val alert = PopupAlertManager.VectorAlert(
+ uniqueIdForVerificationRequest(pr),
+ context.getString(R.string.sas_incoming_request_notif_title),
+ "$name(${pr.otherUserId})",
+ R.drawable.ic_shield_black,
+ shouldBeDisplayedIn = { activity ->
+ if (activity is RoomDetailActivity) {
+ activity.intent?.extras?.getParcelable(RoomDetailActivity.EXTRA_ROOM_DETAIL_ARGS)?.let {
+ it.roomId != pr.roomId
+ } ?: true
+ } else true
+ })
+ .apply {
+ contentAction = Runnable {
+ (weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
+ it.navigator.openRoom(it, pr.roomId ?: "", pr.transactionId)
+ }
+ }
+ dismissedAction = Runnable {
+ session?.getSasVerificationService()?.declineVerificationRequestInDMs(pr.otherUserId,
+ pr.requestInfo?.fromDevice ?: "",
+ pr.transactionId ?: "",
+ pr.roomId ?: ""
+ )
+ }
+ colorInt = ThemeUtils.getColor(context, R.attr.vctr_notice_secondary)
+ // 5mn expiration
+ expirationTimestamp = System.currentTimeMillis() + (5 * 60 * 1000L)
+ }
+ PopupAlertManager.postVectorAlert(alert)
+ }
+ }
+
+ override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
+ // If an incoming request is readied (by another device?) we should discard the alert
+ if (pr.isIncoming && (pr.isReady || pr.handledByOtherSession)) {
+ PopupAlertManager.cancelAlert(uniqueIdForVerificationRequest(pr))
+ }
+ super.verificationRequestUpdated(pr)
+ }
+
+ private fun uniqueIdForVerificationRequest(pr: PendingVerificationRequest) =
+ "verificationRequest_${pr.transactionId}"
}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt
deleted file mode 100644
index 222891eb3d..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.app.Activity
-import android.content.Context
-import android.content.Intent
-import android.view.MenuItem
-import androidx.appcompat.app.AlertDialog
-import androidx.lifecycle.Observer
-import im.vector.matrix.android.api.session.crypto.sas.CancelCode
-import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction
-import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
-import im.vector.riotx.R
-import im.vector.riotx.core.extensions.commitTransaction
-import im.vector.riotx.core.extensions.observeEvent
-import im.vector.riotx.core.platform.SimpleFragmentActivity
-import im.vector.riotx.core.platform.WaitingViewData
-
-// TODO Deprecated("replaced by bottomsheet UX")
-class SASVerificationActivity : SimpleFragmentActivity() {
-
- companion object {
-
- private const val EXTRA_MATRIX_ID = "EXTRA_MATRIX_ID"
- private const val EXTRA_TRANSACTION_ID = "EXTRA_TRANSACTION_ID"
- private const val EXTRA_OTHER_USER_ID = "EXTRA_OTHER_USER_ID"
- private const val EXTRA_OTHER_DEVICE_ID = "EXTRA_OTHER_DEVICE_ID"
- private const val EXTRA_IS_INCOMING = "EXTRA_IS_INCOMING"
-
- /* ==========================================================================================
- * INPUT
- * ========================================================================================== */
-
- fun incomingIntent(context: Context, matrixID: String, otherUserId: String, transactionID: String): Intent {
- val intent = Intent(context, SASVerificationActivity::class.java)
- intent.putExtra(EXTRA_MATRIX_ID, matrixID)
- intent.putExtra(EXTRA_TRANSACTION_ID, transactionID)
- intent.putExtra(EXTRA_OTHER_USER_ID, otherUserId)
- intent.putExtra(EXTRA_IS_INCOMING, true)
- return intent
- }
-
- fun outgoingIntent(context: Context, matrixID: String, otherUserId: String, otherDeviceId: String): Intent {
- val intent = Intent(context, SASVerificationActivity::class.java)
- intent.putExtra(EXTRA_MATRIX_ID, matrixID)
- intent.putExtra(EXTRA_OTHER_DEVICE_ID, otherDeviceId)
- intent.putExtra(EXTRA_OTHER_USER_ID, otherUserId)
- intent.putExtra(EXTRA_IS_INCOMING, false)
- return intent
- }
-
- /* ==========================================================================================
- * OUTPUT
- * ========================================================================================== */
-
- fun getOtherUserId(intent: Intent?): String? {
- return intent?.getStringExtra(EXTRA_OTHER_USER_ID)
- }
-
- fun getOtherDeviceId(intent: Intent?): String? {
- return intent?.getStringExtra(EXTRA_OTHER_DEVICE_ID)
- }
- }
-
- override fun getTitleRes() = R.string.title_activity_verify_device
-
- private lateinit var viewModel: SasVerificationViewModel
-
- override fun initUiAndData() {
- super.initUiAndData()
- viewModel = viewModelProvider.get(SasVerificationViewModel::class.java)
- val transactionID: String? = intent.getStringExtra(EXTRA_TRANSACTION_ID)
-
- if (isFirstCreation()) {
- val isIncoming = intent.getBooleanExtra(EXTRA_IS_INCOMING, false)
- if (isIncoming) {
- // incoming always have a transaction id
- viewModel.initIncoming(session, intent.getStringExtra(EXTRA_OTHER_USER_ID), transactionID)
- } else {
- viewModel.initOutgoing(session, intent.getStringExtra(EXTRA_OTHER_USER_ID), intent.getStringExtra(EXTRA_OTHER_DEVICE_ID))
- }
-
- if (isIncoming) {
- val incoming = viewModel.transaction as? IncomingSasVerificationTransaction
- when (incoming?.uxState) {
- null,
- IncomingSasVerificationTransaction.UxState.UNKNOWN,
- IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT,
- IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT -> {
- supportActionBar?.setTitle(R.string.sas_incoming_request_title)
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationIncomingFragment::class.java, null)
- }
- }
- IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION,
- IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
- }
- }
- IncomingSasVerificationTransaction.UxState.VERIFIED -> {
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
- }
- }
- IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME,
- IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER -> {
- viewModel.navigateCancel()
- }
- }
- } else {
- val outgoing = viewModel.transaction as? OutgoingSasVerificationRequest
- // transaction can be null, as not yet created
- when (outgoing?.uxState) {
- null,
- OutgoingSasVerificationRequest.UxState.UNKNOWN,
- OutgoingSasVerificationRequest.UxState.WAIT_FOR_START,
- OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT -> {
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationStartFragment::class.java, null)
- }
- }
- OutgoingSasVerificationRequest.UxState.SHOW_SAS,
- OutgoingSasVerificationRequest.UxState.WAIT_FOR_VERIFICATION -> {
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
- }
- }
- OutgoingSasVerificationRequest.UxState.VERIFIED -> {
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
- }
- }
- OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME,
- OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> {
- viewModel.navigateCancel()
- }
- }
- }
- }
-
- viewModel.navigateEvent.observeEvent(this) { uxStateEvent ->
- when (uxStateEvent) {
- SasVerificationViewModel.NAVIGATE_FINISH -> {
- finish()
- }
- SasVerificationViewModel.NAVIGATE_FINISH_SUCCESS -> {
- val dataResult = Intent()
- dataResult.putExtra(EXTRA_OTHER_DEVICE_ID, viewModel.otherDeviceId)
- dataResult.putExtra(EXTRA_OTHER_USER_ID, viewModel.otherUserId)
- setResult(Activity.RESULT_OK, dataResult)
- finish()
- }
- SasVerificationViewModel.NAVIGATE_SAS_DISPLAY -> {
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
- }
- }
- SasVerificationViewModel.NAVIGATE_SUCCESS -> {
- supportFragmentManager.commitTransaction {
- setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
- replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
- }
- }
- SasVerificationViewModel.NAVIGATE_CANCELLED -> {
- val isCancelledByMe = viewModel.transaction?.state == SasVerificationTxState.Cancelled
- val humanReadableReason = when (viewModel.transaction?.cancelledReason) {
- CancelCode.User -> getString(R.string.sas_error_m_user)
- CancelCode.Timeout -> getString(R.string.sas_error_m_timeout)
- CancelCode.UnknownTransaction -> getString(R.string.sas_error_m_unknown_transaction)
- CancelCode.UnknownMethod -> getString(R.string.sas_error_m_unknown_method)
- CancelCode.MismatchedCommitment -> getString(R.string.sas_error_m_mismatched_commitment)
- CancelCode.MismatchedSas -> getString(R.string.sas_error_m_mismatched_sas)
- CancelCode.UnexpectedMessage -> getString(R.string.sas_error_m_unexpected_message)
- CancelCode.InvalidMessage -> getString(R.string.sas_error_m_invalid_message)
- CancelCode.MismatchedKeys -> getString(R.string.sas_error_m_key_mismatch)
- // Use user error
- CancelCode.UserMismatchError -> getString(R.string.sas_error_m_user_error)
- null -> getString(R.string.sas_error_unknown)
- }
- val message =
- if (isCancelledByMe) getString(R.string.sas_cancelled_by_me, humanReadableReason)
- else getString(R.string.sas_cancelled_by_other, humanReadableReason)
- // Show a dialog
- if (!this.isFinishing) {
- AlertDialog.Builder(this)
- .setTitle(R.string.sas_cancelled_dialog_title)
- .setMessage(message)
- .setCancelable(false)
- .setPositiveButton(R.string.ok) { _, _ ->
- // nop
- finish()
- }
- .show()
- }
- }
- }
- }
-
- viewModel.loadingLiveEvent.observe(this, Observer {
- if (it == null) {
- hideWaitingView()
- } else {
- val status = if (it == -1) "" else getString(it)
- updateWaitingView(WaitingViewData(status, isIndeterminate = true))
- }
- })
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) {
- // we want to cancel the transaction
- viewModel.cancelTransaction()
- }
-
- return super.onOptionsItemSelected(item)
- }
-
- override fun onBackPressed() {
- // we want to cancel the transaction
- viewModel.cancelTransaction()
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationCodeFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationCodeFragment.kt
deleted file mode 100644
index 122af8b625..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationCodeFragment.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.core.view.isInvisible
-import androidx.core.view.isVisible
-import butterknife.BindView
-import butterknife.OnClick
-import com.airbnb.mvrx.*
-import im.vector.riotx.R
-import im.vector.riotx.core.platform.VectorBaseFragment
-import kotlinx.android.synthetic.main.fragment_bottom_sas_verification_code.*
-import javax.inject.Inject
-
-class SASVerificationCodeFragment @Inject constructor(
- val viewModelFactory: SASVerificationCodeViewModel.Factory
-) : VectorBaseFragment() {
-
- override fun getLayoutResId() = R.layout.fragment_bottom_sas_verification_code
-
- @BindView(R.id.sas_emoji_grid)
- lateinit var emojiGrid: ViewGroup
-
- @BindView(R.id.sas_decimal_code)
- lateinit var decimalTextView: TextView
-
- @BindView(R.id.emoji0)
- lateinit var emoji0View: ViewGroup
- @BindView(R.id.emoji1)
- lateinit var emoji1View: ViewGroup
- @BindView(R.id.emoji2)
- lateinit var emoji2View: ViewGroup
- @BindView(R.id.emoji3)
- lateinit var emoji3View: ViewGroup
- @BindView(R.id.emoji4)
- lateinit var emoji4View: ViewGroup
- @BindView(R.id.emoji5)
- lateinit var emoji5View: ViewGroup
- @BindView(R.id.emoji6)
- lateinit var emoji6View: ViewGroup
-
- private val viewModel by fragmentViewModel(SASVerificationCodeViewModel::class)
-
- private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
-
- override fun invalidate() = withState(viewModel) { state ->
-
- if (state.supportsEmoji) {
- decimalTextView.isVisible = false
- when (val emojiDescription = state.emojiDescription) {
- is Success -> {
- sasLoadingProgress.isVisible = false
- emojiGrid.isVisible = true
- ButtonsVisibilityGroup.isVisible = true
- emojiDescription.invoke().forEachIndexed { index, emojiRepresentation ->
- when (index) {
- 0 -> {
- emoji0View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji0View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 1 -> {
- emoji1View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji1View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 2 -> {
- emoji2View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji2View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 3 -> {
- emoji3View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji3View.findViewById(R.id.item_emoji_name_tv)?.setText(emojiRepresentation.nameResId)
- }
- 4 -> {
- emoji4View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji4View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 5 -> {
- emoji5View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji5View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 6 -> {
- emoji6View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji6View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- }
- }
-
- if (state.isWaitingFromOther) {
- // hide buttons
- ButtonsVisibilityGroup.isInvisible = true
- sasCodeWaitingPartnerText.isVisible = true
- } else {
- ButtonsVisibilityGroup.isVisible = true
- sasCodeWaitingPartnerText.isVisible = false
- }
- }
- is Fail -> {
- sasLoadingProgress.isVisible = false
- emojiGrid.isInvisible = true
- ButtonsVisibilityGroup.isInvisible = true
- // TODO?
- }
- else -> {
- sasLoadingProgress.isVisible = true
- emojiGrid.isInvisible = true
- ButtonsVisibilityGroup.isInvisible = true
- }
- }
- } else {
- // Decimal
- emojiGrid.isInvisible = true
- decimalTextView.isVisible = true
- val decimalCode = state.decimalDescription.invoke()
- decimalTextView.text = decimalCode
-
- // TODO
- if (state.isWaitingFromOther) {
- // hide buttons
- ButtonsVisibilityGroup.isInvisible = true
- sasCodeWaitingPartnerText.isVisible = true
- } else {
- ButtonsVisibilityGroup.isVisible = decimalCode != null
- sasCodeWaitingPartnerText.isVisible = false
- }
- }
- }
-
- @OnClick(R.id.sas_request_continue_button)
- fun onMatchButtonTapped() = withState(viewModel) { state ->
- val otherUserId = state.otherUser?.id ?: return@withState
- val txId = state.transactionId ?: return@withState
- // UX echo
- ButtonsVisibilityGroup.isInvisible = true
- sasCodeWaitingPartnerText.isVisible = true
- sharedViewModel.handle(VerificationAction.SASMatchAction(otherUserId, txId))
- }
-
- @OnClick(R.id.sas_request_cancel_button)
- fun onDoNotMatchButtonTapped() = withState(viewModel) { state ->
- val otherUserId = state.otherUser?.id ?: return@withState
- val txId = state.transactionId ?: return@withState
- // UX echo
- ButtonsVisibilityGroup.isInvisible = true
- sasCodeWaitingPartnerText.isVisible = true
- sharedViewModel.handle(VerificationAction.SASDoNotMatchAction(otherUserId, txId))
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt
deleted file mode 100644
index cb96900ba7..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.os.Bundle
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.lifecycle.Observer
-import butterknife.BindView
-import butterknife.OnClick
-import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction
-import im.vector.matrix.android.api.util.MatrixItem
-import im.vector.matrix.android.api.util.toMatrixItem
-import im.vector.riotx.R
-import im.vector.riotx.core.platform.VectorBaseFragment
-import im.vector.riotx.features.home.AvatarRenderer
-import javax.inject.Inject
-
-// TODO Deprecated("replaced by bottomsheet UX")
-class SASVerificationIncomingFragment @Inject constructor(
- private var avatarRenderer: AvatarRenderer
-) : VectorBaseFragment() {
-
- @BindView(R.id.sas_incoming_request_user_display_name)
- lateinit var otherUserDisplayNameTextView: TextView
-
- @BindView(R.id.sas_incoming_request_user_id)
- lateinit var otherUserIdTextView: TextView
-
- @BindView(R.id.sas_incoming_request_user_device)
- lateinit var otherDeviceTextView: TextView
-
- @BindView(R.id.sas_incoming_request_user_avatar)
- lateinit var avatarImageView: ImageView
-
- override fun getLayoutResId() = R.layout.fragment_sas_verification_incoming_request
-
- private lateinit var viewModel: SasVerificationViewModel
-
- override fun onActivityCreated(savedInstanceState: Bundle?) {
- super.onActivityCreated(savedInstanceState)
-
- viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java)
-
- otherUserDisplayNameTextView.text = viewModel.otherUser?.displayName ?: viewModel.otherUserId
- otherUserIdTextView.text = viewModel.otherUserId
- otherDeviceTextView.text = viewModel.otherDeviceId
-
- viewModel.otherUser?.let {
- avatarRenderer.render(it.toMatrixItem(), avatarImageView)
- } ?: run {
- // Fallback to what we know
- avatarRenderer.render(MatrixItem.UserItem(viewModel.otherUserId ?: "", viewModel.otherUserId), avatarImageView)
- }
-
- viewModel.transactionState.observe(viewLifecycleOwner, Observer {
- val uxState = (viewModel.transaction as? IncomingSasVerificationTransaction)?.uxState
- when (uxState) {
- IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
- viewModel.loadingLiveEvent.value = null
- }
- IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT -> {
- viewModel.loadingLiveEvent.value = R.string.sas_waiting_for_partner
- }
- IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
- viewModel.shortCodeReady()
- }
- IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME,
- IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER -> {
- viewModel.loadingLiveEvent.value = null
- viewModel.navigateCancel()
- }
- else -> Unit
- }
- })
- }
-
- @OnClick(R.id.sas_request_continue_button)
- fun didAccept() {
- viewModel.acceptTransaction()
- }
-
- @OnClick(R.id.sas_request_cancel_button)
- fun didCancel() {
- viewModel.cancelTransaction()
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt
deleted file mode 100644
index 64c1c4b1f0..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.os.Bundle
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.core.view.isInvisible
-import androidx.core.view.isVisible
-import androidx.lifecycle.Observer
-import butterknife.BindView
-import butterknife.OnClick
-import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction
-import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
-import im.vector.riotx.R
-import im.vector.riotx.core.platform.VectorBaseFragment
-import javax.inject.Inject
-
-// TODO Deprecated("replaced by bottomsheet UX")
-class SASVerificationShortCodeFragment @Inject constructor(): VectorBaseFragment() {
-
- private lateinit var viewModel: SasVerificationViewModel
-
- @BindView(R.id.sas_decimal_code)
- lateinit var decimalTextView: TextView
-
- @BindView(R.id.sas_emoji_description)
- lateinit var descriptionTextView: TextView
-
- @BindView(R.id.sas_emoji_grid)
- lateinit var emojiGrid: ViewGroup
-
- @BindView(R.id.emoji0)
- lateinit var emoji0View: ViewGroup
- @BindView(R.id.emoji1)
- lateinit var emoji1View: ViewGroup
- @BindView(R.id.emoji2)
- lateinit var emoji2View: ViewGroup
- @BindView(R.id.emoji3)
- lateinit var emoji3View: ViewGroup
- @BindView(R.id.emoji4)
- lateinit var emoji4View: ViewGroup
- @BindView(R.id.emoji5)
- lateinit var emoji5View: ViewGroup
- @BindView(R.id.emoji6)
- lateinit var emoji6View: ViewGroup
-
- override fun getLayoutResId() = R.layout.fragment_sas_verification_display_code
-
- override fun onActivityCreated(savedInstanceState: Bundle?) {
- super.onActivityCreated(savedInstanceState)
- viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java)
-
- viewModel.transaction?.let {
- if (it.supportsEmoji()) {
- val emojicodes = it.getEmojiCodeRepresentation()
- emojicodes.forEachIndexed { index, emojiRepresentation ->
- when (index) {
- 0 -> {
- emoji0View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji0View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 1 -> {
- emoji1View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji1View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 2 -> {
- emoji2View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji2View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 3 -> {
- emoji3View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji3View.findViewById(R.id.item_emoji_name_tv)?.setText(emojiRepresentation.nameResId)
- }
- 4 -> {
- emoji4View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji4View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 5 -> {
- emoji5View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji5View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- 6 -> {
- emoji6View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji
- emoji6View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
- }
- }
- }
- }
-
- // decimal is at least supported
- decimalTextView.text = it.getDecimalCodeRepresentation()
-
- if (it.supportsEmoji()) {
- descriptionTextView.text = getString(R.string.sas_emoji_description)
- decimalTextView.isVisible = false
- emojiGrid.isVisible = true
- } else {
- descriptionTextView.text = getString(R.string.sas_decimal_description)
- decimalTextView.isVisible = true
- emojiGrid.isInvisible = true
- }
- }
-
- viewModel.transactionState.observe(viewLifecycleOwner, Observer {
- if (viewModel.transaction is IncomingSasVerificationTransaction) {
- val uxState = (viewModel.transaction as IncomingSasVerificationTransaction).uxState
- when (uxState) {
- IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
- viewModel.loadingLiveEvent.value = null
- }
- IncomingSasVerificationTransaction.UxState.VERIFIED -> {
- viewModel.loadingLiveEvent.value = null
- viewModel.deviceIsVerified()
- }
- IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME,
- IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER -> {
- viewModel.loadingLiveEvent.value = null
- viewModel.navigateCancel()
- }
- else -> {
- viewModel.loadingLiveEvent.value = R.string.sas_waiting_for_partner
- }
- }
- } else if (viewModel.transaction is OutgoingSasVerificationRequest) {
- val uxState = (viewModel.transaction as OutgoingSasVerificationRequest).uxState
- when (uxState) {
- OutgoingSasVerificationRequest.UxState.SHOW_SAS -> {
- viewModel.loadingLiveEvent.value = null
- }
- OutgoingSasVerificationRequest.UxState.VERIFIED -> {
- viewModel.loadingLiveEvent.value = null
- viewModel.deviceIsVerified()
- }
- OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME,
- OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> {
- viewModel.loadingLiveEvent.value = null
- viewModel.navigateCancel()
- }
- else -> {
- viewModel.loadingLiveEvent.value = R.string.sas_waiting_for_partner
- }
- }
- }
- })
- }
-
- @OnClick(R.id.sas_request_continue_button)
- fun didAccept() {
- viewModel.confirmEmojiSame()
- }
-
- @OnClick(R.id.sas_request_cancel_button)
- fun didCancel() {
- viewModel.cancelTransaction()
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt
deleted file mode 100644
index 4e9699e853..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.os.Bundle
-import android.view.ViewGroup
-import android.widget.Button
-import android.widget.ProgressBar
-import android.widget.TextView
-import androidx.core.view.isInvisible
-import androidx.core.view.isVisible
-import androidx.lifecycle.Observer
-import androidx.transition.TransitionManager
-import butterknife.BindView
-import butterknife.OnClick
-import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
-import im.vector.riotx.R
-import im.vector.riotx.core.platform.VectorBaseActivity
-import im.vector.riotx.core.platform.VectorBaseFragment
-import javax.inject.Inject
-
-// TODO Deprecated("replaced by bottomsheet UX")
-class SASVerificationStartFragment @Inject constructor(): VectorBaseFragment() {
-
- override fun getLayoutResId() = R.layout.fragment_sas_verification_start
-
- private lateinit var viewModel: SasVerificationViewModel
-
- @BindView(R.id.rootLayout)
- lateinit var rootLayout: ViewGroup
-
- @BindView(R.id.sas_start_button)
- lateinit var startButton: Button
-
- @BindView(R.id.sas_start_button_loading)
- lateinit var startButtonLoading: ProgressBar
-
- @BindView(R.id.sas_verifying_keys)
- lateinit var loadingText: TextView
-
- override fun onActivityCreated(savedInstanceState: Bundle?) {
- super.onActivityCreated(savedInstanceState)
- viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java)
- viewModel.transactionState.observe(viewLifecycleOwner, Observer {
- val uxState = (viewModel.transaction as? OutgoingSasVerificationRequest)?.uxState
- when (uxState) {
- OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT -> {
- // display loading
- TransitionManager.beginDelayedTransition(this.rootLayout)
- this.loadingText.isVisible = true
- this.startButton.isInvisible = true
- this.startButtonLoading.isVisible = true
- this.startButtonLoading.animate()
- }
- OutgoingSasVerificationRequest.UxState.SHOW_SAS -> {
- viewModel.shortCodeReady()
- }
- OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME,
- OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> {
- viewModel.navigateCancel()
- }
- else -> {
- TransitionManager.beginDelayedTransition(this.rootLayout)
- this.loadingText.isVisible = false
- this.startButton.isVisible = true
- this.startButtonLoading.isVisible = false
- }
- }
- })
- }
-
- @OnClick(R.id.sas_start_button)
- fun doStart() {
- viewModel.beginSasKeyVerification()
- }
-
- @OnClick(R.id.sas_legacy_verification)
- fun doLegacy() {
- (requireActivity() as VectorBaseActivity).notImplemented()
-
- /*
- viewModel.session.crypto?.getDeviceInfo(viewModel.otherUserMxItem ?: "", viewModel.otherDeviceId
- ?: "", object : SimpleApiCallback() {
- override fun onSuccess(info: MXDeviceInfo?) {
- info?.let {
-
- CommonActivityUtils.displayDeviceVerificationDialogLegacy(it, it.userId, viewModel.session, activity, object : YesNoListener {
- override fun yes() {
- viewModel.manuallyVerified()
- }
-
- override fun no() {
-
- }
- })
- }
- }
- })
- */
- }
-
- @OnClick(R.id.sas_cancel_button)
- fun doCancel() {
- // Transaction may be started, or not
- viewModel.cancelTransaction()
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt
deleted file mode 100644
index fe7f9861b0..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.os.Bundle
-import butterknife.OnClick
-import im.vector.riotx.R
-import im.vector.riotx.core.platform.VectorBaseFragment
-import javax.inject.Inject
-
-// TODO Deprecated("replaced by bottomsheet UX")
-class SASVerificationVerifiedFragment @Inject constructor() : VectorBaseFragment() {
-
- override fun getLayoutResId() = R.layout.fragment_sas_verification_verified
-
- private lateinit var viewModel: SasVerificationViewModel
-
- override fun onActivityCreated(savedInstanceState: Bundle?) {
- super.onActivityCreated(savedInstanceState)
-
- viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java)
- }
-
- @OnClick(R.id.sas_verification_verified_done_button)
- fun onDone() {
- viewModel.finishSuccess()
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SasVerificationViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SasVerificationViewModel.kt
deleted file mode 100644
index ca283e449d..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SasVerificationViewModel.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import im.vector.matrix.android.api.session.Session
-import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
-import im.vector.matrix.android.api.session.user.model.User
-import im.vector.riotx.core.utils.LiveEvent
-import javax.inject.Inject
-
-// TODO Deprecated("replaced by bottomsheet UX")
-class SasVerificationViewModel @Inject constructor() : ViewModel(),
- SasVerificationService.SasVerificationListener {
-
- companion object {
- const val NAVIGATE_FINISH = "NAVIGATE_FINISH"
- const val NAVIGATE_FINISH_SUCCESS = "NAVIGATE_FINISH_SUCCESS"
- const val NAVIGATE_SAS_DISPLAY = "NAVIGATE_SAS_DISPLAY"
- const val NAVIGATE_SUCCESS = "NAVIGATE_SUCCESS"
- const val NAVIGATE_CANCELLED = "NAVIGATE_CANCELLED"
- }
-
- private lateinit var sasVerificationService: SasVerificationService
-
- var otherUserId: String? = null
- var otherDeviceId: String? = null
- var otherUser: User? = null
- var transaction: SasVerificationTransaction? = null
-
- var transactionState: MutableLiveData = MutableLiveData()
-
- init {
- // Force a first observe
- transactionState.value = null
- }
-
- private var _navigateEvent: MutableLiveData> = MutableLiveData()
- val navigateEvent: LiveData>
- get() = _navigateEvent
-
- var loadingLiveEvent: MutableLiveData = MutableLiveData()
-
- var transactionID: String? = null
- set(value) {
- if (value != null) {
- transaction = sasVerificationService.getExistingTransaction(otherUserId!!, value)
- transactionState.value = transaction?.state
- otherDeviceId = transaction?.otherDeviceId
- }
- field = value
- }
-
- fun initIncoming(session: Session, otherUserId: String, transactionID: String?) {
- this.sasVerificationService = session.getSasVerificationService()
- this.otherUserId = otherUserId
- this.transactionID = transactionID
- this.sasVerificationService.addListener(this)
- this.otherUser = session.getUser(otherUserId)
- if (transactionID == null || transaction == null) {
- // sanity, this transaction is not known anymore
- _navigateEvent.value = LiveEvent(NAVIGATE_FINISH)
- }
- }
-
- fun initOutgoing(session: Session, otherUserId: String, otherDeviceId: String) {
- this.sasVerificationService = session.getSasVerificationService()
- this.otherUserId = otherUserId
- this.otherDeviceId = otherDeviceId
- this.sasVerificationService.addListener(this)
- this.otherUser = session.getUser(otherUserId)
- }
-
- fun beginSasKeyVerification() {
- val verificationSAS = sasVerificationService.beginKeyVerificationSAS(otherUserId!!, otherDeviceId!!)
- this.transactionID = verificationSAS
- }
-
- override fun transactionCreated(tx: SasVerificationTransaction) {
- }
-
- override fun transactionUpdated(tx: SasVerificationTransaction) {
- if (transactionID == tx.transactionId) {
- transactionState.value = tx.state
- }
- }
-
- override fun markedAsManuallyVerified(userId: String, deviceId: String) {
- }
-
- fun cancelTransaction() {
- transaction?.cancel()
- _navigateEvent.value = LiveEvent(NAVIGATE_FINISH)
- }
-
- fun finishSuccess() {
- _navigateEvent.value = LiveEvent(NAVIGATE_FINISH_SUCCESS)
- }
-
- fun manuallyVerified() {
- if (otherUserId != null && otherDeviceId != null) {
- sasVerificationService.markedLocallyAsManuallyVerified(otherUserId!!, otherDeviceId!!)
- }
- _navigateEvent.value = LiveEvent(NAVIGATE_FINISH_SUCCESS)
- }
-
- fun acceptTransaction() {
- (transaction as? IncomingSasVerificationTransaction)?.performAccept()
- }
-
- fun confirmEmojiSame() {
- transaction?.userHasVerifiedShortCode()
- }
-
- fun shortCodeReady() {
- loadingLiveEvent.value = null
- _navigateEvent.value = LiveEvent(NAVIGATE_SAS_DISPLAY)
- }
-
- fun deviceIsVerified() {
- loadingLiveEvent.value = null
- _navigateEvent.value = LiveEvent(NAVIGATE_SUCCESS)
- }
-
- fun navigateCancel() {
- _navigateEvent.value = LiveEvent(NAVIGATE_CANCELLED)
- }
-
- override fun onCleared() {
- super.onCleared()
- if (::sasVerificationService.isInitialized) {
- sasVerificationService.removeListener(this)
- }
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt
index 61598bd5fc..22369f37b5 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt
@@ -17,20 +17,16 @@ package im.vector.riotx.features.crypto.verification
import android.os.Bundle
import android.os.Parcelable
-import android.view.LayoutInflater
import android.view.View
-import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.coordinatorlayout.widget.CoordinatorLayout
-import androidx.core.text.toSpannable
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.transition.AutoTransition
import androidx.transition.TransitionManager
import butterknife.BindView
-import butterknife.ButterKnife
-import butterknife.Unbinder
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.fragmentViewModel
@@ -40,9 +36,12 @@ import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.commitTransactionNow
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
-import im.vector.riotx.core.utils.colorizeMatchingText
+import im.vector.riotx.features.crypto.verification.choose.VerificationChooseMethodFragment
+import im.vector.riotx.features.crypto.verification.conclusion.VerificationConclusionFragment
+import im.vector.riotx.features.crypto.verification.emoji.VerificationEmojiCodeFragment
+import im.vector.riotx.features.crypto.verification.request.VerificationRequestFragment
+import im.vector.riotx.features.crypto.verification.request.VerificationRequestViewModel
import im.vector.riotx.features.home.AvatarRenderer
-import im.vector.riotx.features.themes.ThemeUtils
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_verification.*
import timber.log.Timber
@@ -74,22 +73,13 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
@BindView(R.id.verificationRequestName)
lateinit var otherUserNameText: TextView
+ @BindView(R.id.verificationRequestShield)
+ lateinit var otherUserShield: View
+
@BindView(R.id.verificationRequestAvatar)
lateinit var otherUserAvatarImageView: ImageView
- private var unBinder: Unbinder? = null
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.bottom_sheet_verification, container, false)
- unBinder = ButterKnife.bind(this, view)
- return view
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- unBinder?.unbind()
- unBinder = null
- }
+ override fun getLayoutResId() = R.layout.bottom_sheet_verification
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -109,12 +99,15 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
override fun invalidate() = withState(viewModel) {
it.otherUserMxItem?.let { matrixItem ->
- val displayName = matrixItem.displayName ?: ""
- otherUserNameText.text = getString(R.string.verification_request_alert_title, displayName)
- .toSpannable()
- .colorizeMatchingText(displayName, ThemeUtils.getColor(requireContext(), R.attr.vctr_notice_text_color))
-
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
+
+ if(it.sasTransactionState == SasVerificationTxState.Verified) {
+ otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
+ otherUserShield.isVisible = true
+ } else {
+ otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
+ otherUserShield.isVisible = false
+ }
}
// Did the request result in a SAS transaction?
@@ -135,7 +128,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
SasVerificationTxState.SendingMac,
SasVerificationTxState.MacSent,
SasVerificationTxState.Verifying -> {
- showFragment(SASVerificationCodeFragment::class, Bundle().apply {
+ showFragment(VerificationEmojiCodeFragment::class, Bundle().apply {
putParcelable(MvRx.KEY_ARG, VerificationArgs(
it.otherUserMxItem?.id ?: "",
it.pendingRequest?.transactionId))
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt
index e25a22e668..20383b306d 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt
@@ -21,13 +21,9 @@ import com.airbnb.mvrx.*
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
-import im.vector.matrix.android.api.session.crypto.sas.CancelCode
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
-import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
+import im.vector.matrix.android.api.session.crypto.sas.*
import im.vector.matrix.android.api.util.MatrixItem
import im.vector.matrix.android.api.util.toMatrixItem
-import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.VectorViewModel
@@ -108,7 +104,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
is VerificationAction.RequestVerificationByDM -> {
// session
setState {
- copy(pendingRequest = session.getSasVerificationService().requestKeyVerificationInDMs(otherUserId, roomId))
+ copy(pendingRequest = session.getSasVerificationService().requestKeyVerificationInDMs(supportedVerificationMethods, otherUserId, roomId))
}
}
is VerificationAction.StartSASVerification -> {
@@ -117,7 +113,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
val otherDevice = if (request.isIncoming) request.requestInfo?.fromDevice else request.readyInfo?.fromDevice
session.getSasVerificationService().beginKeyVerificationInDMs(
- KeyVerificationStart.VERIF_METHOD_SAS,
+ VerificationMethod.SAS,
transactionId = action.pendingRequestTransactionId,
roomId = roomId,
otherUserId = request.otherUserId,
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationChooseMethodFragment.kt
deleted file mode 100644
index 69abc77b6f..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationChooseMethodFragment.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.text.style.ClickableSpan
-import android.view.View
-import androidx.core.text.toSpannable
-import androidx.core.view.isVisible
-import butterknife.OnClick
-import com.airbnb.mvrx.fragmentViewModel
-import com.airbnb.mvrx.parentFragmentViewModel
-import com.airbnb.mvrx.withState
-import im.vector.riotx.R
-import im.vector.riotx.core.platform.VectorBaseFragment
-import im.vector.riotx.core.utils.tappableMatchingText
-import kotlinx.android.synthetic.main.fragment_verification_choose_method.*
-import javax.inject.Inject
-
-class VerificationChooseMethodFragment @Inject constructor(
- val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory
-) : VectorBaseFragment() {
-
- override fun getLayoutResId() = R.layout.fragment_verification_choose_method
-
- private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
-
- private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
-
- override fun invalidate() = withState(viewModel) { state ->
- if (state.QRModeAvailable) {
- val cSpan = object : ClickableSpan() {
- override fun onClick(widget: View) {
- }
- }
- val openLink = getString(R.string.verify_open_camera_link)
- val descCharSequence =
- getString(R.string.verify_by_scanning_description, openLink)
- .toSpannable()
- .tappableMatchingText(openLink, cSpan)
- verifyQRDescription.text = descCharSequence
- verifyQRGroup.isVisible = true
- } else {
- verifyQRGroup.isVisible = false
- }
-
- verifyEmojiGroup.isVisible = state.SASMOdeAvailable
- }
-
- @OnClick(R.id.verificationByEmojiButton)
- fun doVerifyBySas() = withState(sharedViewModel) {
- sharedViewModel.handle(VerificationAction.StartSASVerification(it.otherUserMxItem?.id ?: "", it.pendingRequest?.transactionId
- ?: ""))
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationConclusionFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationConclusionFragment.kt
deleted file mode 100644
index fdf4b0cbd4..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationConclusionFragment.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.os.Parcelable
-import androidx.core.content.ContextCompat
-import androidx.core.view.isVisible
-import butterknife.OnClick
-import com.airbnb.mvrx.fragmentViewModel
-import com.airbnb.mvrx.parentFragmentViewModel
-import com.airbnb.mvrx.withState
-import im.vector.riotx.R
-import im.vector.riotx.core.extensions.setTextOrHide
-import im.vector.riotx.core.platform.VectorBaseFragment
-import io.noties.markwon.Markwon
-import kotlinx.android.parcel.Parcelize
-import kotlinx.android.synthetic.main.fragment_verification_conclusion.*
-import javax.inject.Inject
-
-class VerificationConclusionFragment @Inject constructor() : VectorBaseFragment() {
-
- @Parcelize
- data class Args(
- val isSuccessFull: Boolean,
- val cancelReason: String?
- ) : Parcelable
-
- override fun getLayoutResId() = R.layout.fragment_verification_conclusion
-
- private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
-
- private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class)
-
- override fun invalidate() = withState(viewModel) {
- when (it.conclusionState) {
- ConclusionState.SUCCESS -> {
- verificationConclusionTitle.text = getString(R.string.sas_verified)
- verifyConclusionDescription.setTextOrHide(getString(R.string.sas_verified_successful_description))
- verifyConclusionBottomDescription.text = getString(R.string.verification_green_shield)
- verifyConclusionImageView.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_shield_trusted))
- }
- ConclusionState.WARNING -> {
- verificationConclusionTitle.text = getString(R.string.verification_conclusion_not_secure)
- verifyConclusionDescription.isVisible = false
- verifyConclusionImageView.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_shield_warning))
-
- verifyConclusionBottomDescription.text = Markwon.builder(requireContext())
- .build()
- .toMarkdown(getString(R.string.verification_conclusion_compromised))
- }
- ConclusionState.CANCELLED -> {
- // Just dismiss in this case
- sharedViewModel.handle(VerificationAction.GotItConclusion)
- }
- }
- }
-
- @OnClick(R.id.verificationConclusionButton)
- fun onButtonTapped() {
- sharedViewModel.handle(VerificationAction.GotItConclusion)
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationRequestFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationRequestFragment.kt
deleted file mode 100644
index d6e4105fdd..0000000000
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationRequestFragment.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package im.vector.riotx.features.crypto.verification
-
-import android.graphics.Typeface
-import androidx.core.text.toSpannable
-import androidx.core.view.isInvisible
-import androidx.core.view.isVisible
-import butterknife.OnClick
-import com.airbnb.mvrx.Loading
-import com.airbnb.mvrx.fragmentViewModel
-import com.airbnb.mvrx.parentFragmentViewModel
-import com.airbnb.mvrx.withState
-import im.vector.riotx.R
-import im.vector.riotx.core.platform.VectorBaseFragment
-import im.vector.riotx.core.utils.colorizeMatchingText
-import im.vector.riotx.core.utils.styleMatchingText
-import im.vector.riotx.features.home.AvatarRenderer
-import im.vector.riotx.features.themes.ThemeUtils
-import kotlinx.android.synthetic.main.fragment_verification_request.*
-import javax.inject.Inject
-
-class VerificationRequestFragment @Inject constructor(
- val verificationRequestViewModelFactory: VerificationRequestViewModel.Factory,
- val avatarRenderer: AvatarRenderer
-) : VectorBaseFragment() {
-
- private val viewModel by fragmentViewModel(VerificationRequestViewModel::class)
-
- private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
-
- override fun getLayoutResId() = R.layout.fragment_verification_request
-
- override fun invalidate() = withState(viewModel) { state ->
- state.matrixItem.let {
- val styledText = getString(R.string.verification_request_alert_description, it.id)
- .toSpannable()
- .styleMatchingText(it.id, Typeface.BOLD)
- .colorizeMatchingText(it.id, ThemeUtils.getColor(requireContext(), R.attr.vctr_notice_text_color))
- verificationRequestText.text = styledText
- }
-
- when (state.started) {
- is Loading -> {
- // Hide the start button, show waiting
- verificationStartButton.isInvisible = true
- verificationWaitingText.isVisible = true
- val otherUser = state.matrixItem.displayName ?: state.matrixItem.id
- verificationWaitingText.text = getString(R.string.verification_request_waiting_for, otherUser)
- .toSpannable()
- .styleMatchingText(otherUser, Typeface.BOLD)
- .colorizeMatchingText(otherUser, ThemeUtils.getColor(requireContext(), R.attr.vctr_notice_text_color))
- }
- else -> {
- verificationStartButton.isEnabled = true
- verificationStartButton.isVisible = true
- verificationWaitingText.isInvisible = true
- }
- }
-
- Unit
- }
-
- @OnClick(R.id.verificationStartButton)
- fun onClickOnVerificationStart() = withState(viewModel) { state ->
- verificationStartButton.isEnabled = false
- sharedViewModel.handle(VerificationAction.RequestVerificationByDM(state.matrixItem.id, state.roomId))
- }
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt
new file mode 100644
index 0000000000..8760a8603e
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotx.features.crypto.verification.choose
+
+import com.airbnb.epoxy.EpoxyController
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.dividerItem
+import im.vector.riotx.core.resources.ColorProvider
+import im.vector.riotx.core.resources.StringProvider
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
+import javax.inject.Inject
+
+class VerificationChooseMethodController @Inject constructor(
+ private val stringProvider: StringProvider,
+ private val colorProvider: ColorProvider
+) : EpoxyController() {
+
+ var listener: Listener? = null
+
+ private var viewState: VerificationChooseMethodViewState? = null
+
+ fun update(viewState: VerificationChooseMethodViewState) {
+ this.viewState = viewState
+ requestModelBuild()
+ }
+
+ override fun buildModels() {
+ val state = viewState ?: return
+
+ if (state.QRModeAvailable) {
+ bottomSheetVerificationNoticeItem {
+ id("notice")
+ notice(stringProvider.getString(R.string.verification_scan_notice))
+ }
+
+ // TODO Generate the QR code
+ bottomSheetVerificationBigImageItem {
+ id("qr")
+ imageRes(R.drawable.riotx_logo)
+ }
+
+ dividerItem {
+ id("sep0")
+ }
+
+ bottomSheetVerificationActionItem {
+ id("openCamera")
+ title(stringProvider.getString(R.string.verification_scan_their_code))
+ titleColor(colorProvider.getColor(R.color.riotx_accent))
+ iconRes(R.drawable.ic_camera)
+ iconColor(colorProvider.getColor(R.color.riotx_accent))
+ listener { listener?.openCamera() }
+ }
+
+ dividerItem {
+ id("sep1")
+ }
+
+ bottomSheetVerificationActionItem {
+ id("openEmoji")
+ title(stringProvider.getString(R.string.verification_scan_emoji_title))
+ titleColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
+ subTitle(stringProvider.getString(R.string.verification_scan_emoji_subtitle))
+ iconRes(R.drawable.ic_arrow_right)
+ iconColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
+ listener { listener?.doVerifyBySas() }
+ }
+ } else if (state.SASModeAvailable) {
+ bottomSheetVerificationActionItem {
+ id("openEmoji")
+ title(stringProvider.getString(R.string.verification_no_scan_emoji_title))
+ titleColor(colorProvider.getColor(R.color.riotx_accent))
+ iconRes(R.drawable.ic_arrow_right)
+ iconColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
+ listener { listener?.doVerifyBySas() }
+ }
+ }
+ }
+
+ interface Listener {
+ fun openCamera()
+ fun doVerifyBySas()
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
new file mode 100644
index 0000000000..b782afca39
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.riotx.features.crypto.verification.choose
+
+import android.os.Bundle
+import android.view.View
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.parentFragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.riotx.R
+import im.vector.riotx.core.extensions.cleanup
+import im.vector.riotx.core.extensions.configureWith
+import im.vector.riotx.core.platform.VectorBaseFragment
+import im.vector.riotx.features.crypto.verification.VerificationAction
+import im.vector.riotx.features.crypto.verification.VerificationBottomSheetViewModel
+import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
+import javax.inject.Inject
+
+class VerificationChooseMethodFragment @Inject constructor(
+ val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory,
+ val controller: VerificationChooseMethodController
+) : VectorBaseFragment(), VerificationChooseMethodController.Listener {
+
+ private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
+
+ private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
+
+ override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupRecyclerView()
+ }
+
+ override fun onDestroyView() {
+ bottomSheetVerificationRecyclerView.cleanup()
+ controller.listener = null
+ super.onDestroyView()
+ }
+
+ private fun setupRecyclerView() {
+ bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
+ controller.listener = this
+ }
+
+ override fun invalidate() = withState(viewModel) { state ->
+ controller.update(state)
+ }
+
+ override fun doVerifyBySas() = withState(sharedViewModel) {
+ sharedViewModel.handle(VerificationAction.StartSASVerification(
+ it.otherUserMxItem?.id ?: "",
+ it.pendingRequest?.transactionId ?: ""))
+ }
+
+ override fun openCamera() {
+ // TODO
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationChooseMethodViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt
similarity index 82%
rename from vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationChooseMethodViewModel.kt
rename to vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt
index 2fcf94a036..a1d566d77b 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationChooseMethodViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package im.vector.riotx.features.crypto.verification
+package im.vector.riotx.features.crypto.verification.choose
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxState
@@ -24,17 +24,18 @@ import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
-import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
+import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.VectorViewModel
+import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
data class VerificationChooseMethodViewState(
val otherUserId: String = "",
val transactionId: String = "",
val QRModeAvailable: Boolean = false,
- val SASMOdeAvailable: Boolean = false
+ val SASModeAvailable: Boolean = false
) : MvRxState
class VerificationChooseMethodViewModel @AssistedInject constructor(
@@ -48,15 +49,13 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
override fun verificationRequestUpdated(pr: PendingVerificationRequest) = withState { state ->
val pvr = session.getSasVerificationService().getExistingVerificationRequest(state.otherUserId, state.transactionId)
- val qrAvailable = pvr?.readyInfo?.methods?.contains(KeyVerificationStart.VERIF_METHOD_SCAN)
- ?: false
- val emojiAvailable = pvr?.readyInfo?.methods?.contains(KeyVerificationStart.VERIF_METHOD_SAS)
- ?: false
+ val qrAvailable = pvr?.hasMethod(VerificationMethod.SCAN) ?: false
+ val emojiAvailable = pvr?.hasMethod(VerificationMethod.SAS) ?: false
setState {
copy(
QRModeAvailable = qrAvailable,
- SASMOdeAvailable = emojiAvailable
+ SASModeAvailable = emojiAvailable
)
}
}
@@ -85,15 +84,13 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
val args: VerificationBottomSheet.VerificationArgs = viewModelContext.args()
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
val pvr = session.getSasVerificationService().getExistingVerificationRequest(args.otherUserId, args.verificationId)
- val qrAvailable = pvr?.readyInfo?.methods?.contains(KeyVerificationStart.VERIF_METHOD_SCAN)
- ?: false
- val emojiAvailable = pvr?.readyInfo?.methods?.contains(KeyVerificationStart.VERIF_METHOD_SAS)
- ?: false
+ val qrAvailable = pvr?.hasMethod(VerificationMethod.SCAN) ?: false
+ val emojiAvailable = pvr?.hasMethod(VerificationMethod.SAS) ?: false
return VerificationChooseMethodViewState(otherUserId = args.otherUserId,
transactionId = args.verificationId ?: "",
QRModeAvailable = qrAvailable,
- SASMOdeAvailable = emojiAvailable
+ SASModeAvailable = emojiAvailable
)
}
}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionController.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionController.kt
new file mode 100644
index 0000000000..5c7e35dc28
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionController.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotx.features.crypto.verification.conclusion
+
+import com.airbnb.epoxy.EpoxyController
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.dividerItem
+import im.vector.riotx.core.resources.ColorProvider
+import im.vector.riotx.core.resources.StringProvider
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
+import im.vector.riotx.features.html.EventHtmlRenderer
+import javax.inject.Inject
+
+class VerificationConclusionController @Inject constructor(
+ private val stringProvider: StringProvider,
+ private val colorProvider: ColorProvider,
+ private val eventHtmlRenderer: EventHtmlRenderer
+) : EpoxyController() {
+
+ var listener: Listener? = null
+
+ private var viewState: VerificationConclusionViewState? = null
+
+ fun update(viewState: VerificationConclusionViewState) {
+ this.viewState = viewState
+ requestModelBuild()
+ }
+
+ override fun buildModels() {
+ val state = viewState ?: return
+
+ when (state.conclusionState) {
+ ConclusionState.SUCCESS -> {
+ bottomSheetVerificationNoticeItem {
+ id("notice")
+ notice(stringProvider.getString(R.string.verification_conclusion_ok_notice))
+ }
+
+ bottomSheetVerificationBigImageItem {
+ id("image")
+ imageRes(R.drawable.ic_shield_trusted)
+ }
+ }
+ ConclusionState.WARNING -> {
+ bottomSheetVerificationNoticeItem {
+ id("notice")
+ notice(stringProvider.getString(R.string.verification_conclusion_not_secure))
+ }
+
+ bottomSheetVerificationBigImageItem {
+ id("image")
+ imageRes(R.drawable.ic_shield_warning)
+ }
+
+ bottomSheetVerificationNoticeItem {
+ id("warning_notice")
+ notice(eventHtmlRenderer.render(stringProvider.getString(R.string.verification_conclusion_compromised)))
+ }
+ }
+ else -> Unit
+ }
+
+ dividerItem {
+ id("sep0")
+ }
+
+ bottomSheetVerificationActionItem {
+ id("done")
+ title(stringProvider.getString(R.string.done))
+ titleColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
+ iconRes(R.drawable.ic_arrow_right)
+ iconColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
+ listener { listener?.onButtonTapped() }
+ }
+ }
+
+ interface Listener {
+ fun onButtonTapped()
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionFragment.kt
new file mode 100644
index 0000000000..a46bb579de
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionFragment.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.riotx.features.crypto.verification.conclusion
+
+import android.os.Bundle
+import android.os.Parcelable
+import android.view.View
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.parentFragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.riotx.R
+import im.vector.riotx.core.extensions.cleanup
+import im.vector.riotx.core.extensions.configureWith
+import im.vector.riotx.core.platform.VectorBaseFragment
+import im.vector.riotx.features.crypto.verification.VerificationAction
+import im.vector.riotx.features.crypto.verification.VerificationBottomSheetViewModel
+import kotlinx.android.parcel.Parcelize
+import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
+import javax.inject.Inject
+
+class VerificationConclusionFragment @Inject constructor(
+ val controller: VerificationConclusionController
+) : VectorBaseFragment(), VerificationConclusionController.Listener {
+
+ @Parcelize
+ data class Args(
+ val isSuccessFull: Boolean,
+ val cancelReason: String?
+ ) : Parcelable
+
+ private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
+
+ private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class)
+
+ override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupRecyclerView()
+ }
+
+ override fun onDestroyView() {
+ bottomSheetVerificationRecyclerView.cleanup()
+ controller.listener = null
+ super.onDestroyView()
+ }
+
+ private fun setupRecyclerView() {
+ bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
+ controller.listener = this
+ }
+
+ override fun invalidate() = withState(viewModel) { state ->
+ if (state.conclusionState == ConclusionState.CANCELLED) {
+ // Just dismiss in this case
+ sharedViewModel.handle(VerificationAction.GotItConclusion)
+ } else {
+ controller.update(state)
+ }
+ }
+
+ override fun onButtonTapped() {
+ sharedViewModel.handle(VerificationAction.GotItConclusion)
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationConclusionViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionViewModel.kt
similarity index 78%
rename from vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationConclusionViewModel.kt
rename to vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionViewModel.kt
index ca069bf853..fc46ba8516 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationConclusionViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/conclusion/VerificationConclusionViewModel.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package im.vector.riotx.features.crypto.verification
+package im.vector.riotx.features.crypto.verification.conclusion
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
@@ -23,7 +23,7 @@ import im.vector.matrix.android.api.session.crypto.sas.safeValueOf
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.VectorViewModel
-data class SASVerificationConclusionViewState(
+data class VerificationConclusionViewState(
val conclusionState: ConclusionState = ConclusionState.CANCELLED
) : MvRxState
@@ -33,22 +33,22 @@ enum class ConclusionState {
CANCELLED
}
-class VerificationConclusionViewModel(initialState: SASVerificationConclusionViewState)
- : VectorViewModel(initialState) {
+class VerificationConclusionViewModel(initialState: VerificationConclusionViewState)
+ : VectorViewModel(initialState) {
- companion object : MvRxViewModelFactory {
+ companion object : MvRxViewModelFactory {
- override fun initialState(viewModelContext: ViewModelContext): SASVerificationConclusionViewState? {
+ override fun initialState(viewModelContext: ViewModelContext): VerificationConclusionViewState? {
val args = viewModelContext.args()
return when (safeValueOf(args.cancelReason)) {
CancelCode.MismatchedSas,
CancelCode.MismatchedCommitment,
CancelCode.MismatchedKeys -> {
- SASVerificationConclusionViewState(ConclusionState.WARNING)
+ VerificationConclusionViewState(ConclusionState.WARNING)
}
else -> {
- SASVerificationConclusionViewState(
+ VerificationConclusionViewState(
if (args.isSuccessFull) ConclusionState.SUCCESS
else ConclusionState.CANCELLED
)
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeController.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeController.kt
new file mode 100644
index 0000000000..12fffd3e11
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeController.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotx.features.crypto.verification.emoji
+
+import com.airbnb.epoxy.EpoxyController
+import com.airbnb.mvrx.Fail
+import com.airbnb.mvrx.Success
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.dividerItem
+import im.vector.riotx.core.epoxy.errorWithRetryItem
+import im.vector.riotx.core.error.ErrorFormatter
+import im.vector.riotx.core.resources.ColorProvider
+import im.vector.riotx.core.resources.StringProvider
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationDecimalCodeItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationEmojisItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
+import javax.inject.Inject
+
+class VerificationEmojiCodeController @Inject constructor(
+ private val stringProvider: StringProvider,
+ private val colorProvider: ColorProvider,
+ private val errorFormatter: ErrorFormatter
+) : EpoxyController() {
+
+ var listener: Listener? = null
+
+ private var viewState: VerificationEmojiCodeViewState? = null
+
+ fun update(viewState: VerificationEmojiCodeViewState) {
+ this.viewState = viewState
+ requestModelBuild()
+ }
+
+ override fun buildModels() {
+ val state = viewState ?: return
+
+ if (state.supportsEmoji) {
+ buildEmojiItem(state)
+ } else {
+ buildDecimal(state)
+ }
+ }
+
+ private fun buildEmojiItem(state: VerificationEmojiCodeViewState) {
+ when (val emojiDescription = state.emojiDescription) {
+ is Success -> {
+ bottomSheetVerificationNoticeItem {
+ id("notice")
+ notice(stringProvider.getString(R.string.verification_emoji_notice))
+ }
+
+ bottomSheetVerificationEmojisItem {
+ id("emojis")
+ emojiRepresentation0(emojiDescription()[0])
+ emojiRepresentation1(emojiDescription()[1])
+ emojiRepresentation2(emojiDescription()[2])
+ emojiRepresentation3(emojiDescription()[3])
+ emojiRepresentation4(emojiDescription()[4])
+ emojiRepresentation5(emojiDescription()[5])
+ emojiRepresentation6(emojiDescription()[6])
+ }
+
+ buildActions(state)
+ }
+ is Fail -> {
+ errorWithRetryItem {
+ id("error")
+ text(errorFormatter.toHumanReadable(emojiDescription.error))
+ }
+ }
+ else -> {
+ bottomSheetVerificationWaitingItem {
+ id("waiting")
+ title(stringProvider.getString(R.string.please_wait))
+ }
+ }
+ }
+ }
+
+ private fun buildDecimal(state: VerificationEmojiCodeViewState) {
+ when (val decimalDescription = state.decimalDescription) {
+ is Success -> {
+ bottomSheetVerificationNoticeItem {
+ id("notice")
+ notice(stringProvider.getString(R.string.verification_code_notice))
+ }
+
+ bottomSheetVerificationDecimalCodeItem {
+ id("decimal")
+ code(state.decimalDescription.invoke() ?: "")
+ }
+
+ buildActions(state)
+ }
+ is Fail -> {
+ errorWithRetryItem {
+ id("error")
+ text(errorFormatter.toHumanReadable(decimalDescription.error))
+ }
+ }
+ else -> {
+ bottomSheetVerificationWaitingItem {
+ id("waiting")
+ title(stringProvider.getString(R.string.please_wait))
+ }
+ }
+ }
+ }
+
+ private fun buildActions(state: VerificationEmojiCodeViewState) {
+ dividerItem {
+ id("sep0")
+ }
+
+ if (state.isWaitingFromOther) {
+ bottomSheetVerificationWaitingItem {
+ id("waiting")
+ title(stringProvider.getString(R.string.verification_request_waiting_for, state.otherUser?.getBestName() ?: ""))
+ }
+ } else {
+ bottomSheetVerificationActionItem {
+ id("ko")
+ title(stringProvider.getString(R.string.verification_sas_do_not_match))
+ titleColor(colorProvider.getColor(R.color.vector_error_color))
+ iconRes(R.drawable.ic_check_off)
+ iconColor(colorProvider.getColor(R.color.vector_error_color))
+ listener { listener?.onDoNotMatchButtonTapped() }
+ }
+ dividerItem {
+ id("sep1")
+ }
+ bottomSheetVerificationActionItem {
+ id("ok")
+ title(stringProvider.getString(R.string.verification_sas_match))
+ titleColor(colorProvider.getColor(R.color.riotx_accent))
+ iconRes(R.drawable.ic_check_on)
+ iconColor(colorProvider.getColor(R.color.riotx_accent))
+ listener { listener?.onMatchButtonTapped() }
+ }
+ }
+ }
+
+ interface Listener {
+ fun onDoNotMatchButtonTapped()
+ fun onMatchButtonTapped()
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
new file mode 100644
index 0000000000..2cd20ca4fb
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.riotx.features.crypto.verification.emoji
+
+import android.os.Bundle
+import android.view.View
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.parentFragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.riotx.R
+import im.vector.riotx.core.extensions.cleanup
+import im.vector.riotx.core.extensions.configureWith
+import im.vector.riotx.core.platform.VectorBaseFragment
+import im.vector.riotx.features.crypto.verification.VerificationAction
+import im.vector.riotx.features.crypto.verification.VerificationBottomSheetViewModel
+import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
+import javax.inject.Inject
+
+class VerificationEmojiCodeFragment @Inject constructor(
+ val viewModelFactory: VerificationEmojiCodeViewModel.Factory,
+ val controller: VerificationEmojiCodeController
+) : VectorBaseFragment(), VerificationEmojiCodeController.Listener {
+
+ private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
+
+ private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
+
+ override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupRecyclerView()
+ }
+
+ override fun onDestroyView() {
+ bottomSheetVerificationRecyclerView.cleanup()
+ controller.listener = null
+ super.onDestroyView()
+ }
+
+ private fun setupRecyclerView() {
+ bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
+ controller.listener = this
+ }
+
+ override fun invalidate() = withState(viewModel) { state ->
+ controller.update(state)
+ }
+
+ override fun onMatchButtonTapped() = withState(viewModel) { state ->
+ val otherUserId = state.otherUser?.id ?: return@withState
+ val txId = state.transactionId ?: return@withState
+ sharedViewModel.handle(VerificationAction.SASMatchAction(otherUserId, txId))
+ }
+
+ override fun onDoNotMatchButtonTapped() = withState(viewModel) { state ->
+ val otherUserId = state.otherUser?.id ?: return@withState
+ val txId = state.transactionId ?: return@withState
+ sharedViewModel.handle(VerificationAction.SASDoNotMatchAction(otherUserId, txId))
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationCodeViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt
similarity index 88%
rename from vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationCodeViewModel.kt
rename to vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt
index cf3a542430..5659dd8291 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationCodeViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package im.vector.riotx.features.crypto.verification
+package im.vector.riotx.features.crypto.verification.emoji
import com.airbnb.mvrx.*
import com.squareup.inject.assisted.Assisted
@@ -28,8 +28,9 @@ import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.VectorViewModel
+import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
-data class SASVerificationCodeViewState(
+data class VerificationEmojiCodeViewState(
val transactionId: String?,
val otherUser: MatrixItem? = null,
val supportsEmoji: Boolean = true,
@@ -38,10 +39,10 @@ data class SASVerificationCodeViewState(
val isWaitingFromOther: Boolean = false
) : MvRxState
-class SASVerificationCodeViewModel @AssistedInject constructor(
- @Assisted initialState: SASVerificationCodeViewState,
+class VerificationEmojiCodeViewModel @AssistedInject constructor(
+ @Assisted initialState: VerificationEmojiCodeViewState,
private val session: Session
-) : VectorViewModel(initialState), SasVerificationService.SasVerificationListener {
+) : VectorViewModel(initialState), SasVerificationService.SasVerificationListener {
init {
withState { state ->
@@ -141,22 +142,22 @@ class SASVerificationCodeViewModel @AssistedInject constructor(
@AssistedInject.Factory
interface Factory {
- fun create(initialState: SASVerificationCodeViewState): SASVerificationCodeViewModel
+ fun create(initialState: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel
}
- companion object : MvRxViewModelFactory {
+ companion object : MvRxViewModelFactory {
- override fun create(viewModelContext: ViewModelContext, state: SASVerificationCodeViewState): SASVerificationCodeViewModel? {
- val factory = (viewModelContext as FragmentViewModelContext).fragment().viewModelFactory
+ override fun create(viewModelContext: ViewModelContext, state: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel? {
+ val factory = (viewModelContext as FragmentViewModelContext).fragment().viewModelFactory
return factory.create(state)
}
- override fun initialState(viewModelContext: ViewModelContext): SASVerificationCodeViewState? {
+ override fun initialState(viewModelContext: ViewModelContext): VerificationEmojiCodeViewState? {
val args = viewModelContext.args()
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
val matrixItem = session.getUser(args.otherUserId)?.toMatrixItem()
- return SASVerificationCodeViewState(
+ return VerificationEmojiCodeViewState(
transactionId = args.verificationId,
otherUser = matrixItem
)
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationActionItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationActionItem.kt
new file mode 100644
index 0000000000..a6b3459701
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationActionItem.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package im.vector.riotx.features.crypto.verification.epoxy
+
+import android.content.res.ColorStateList
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import androidx.core.view.isVisible
+import androidx.core.widget.ImageViewCompat
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.VectorEpoxyHolder
+import im.vector.riotx.core.epoxy.VectorEpoxyModel
+import im.vector.riotx.core.extensions.setTextOrHide
+
+/**
+ * A action for bottom sheet.
+ */
+@EpoxyModelClass(layout = R.layout.item_verification_action)
+abstract class BottomSheetVerificationActionItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ @DrawableRes
+ var iconRes: Int = -1
+ @EpoxyAttribute
+ var title: CharSequence = ""
+ @EpoxyAttribute
+ var subTitle: CharSequence? = null
+ @EpoxyAttribute
+ var titleColor: Int = 0
+ @EpoxyAttribute
+ var iconColor: Int = -1
+
+ @EpoxyAttribute
+ lateinit var listener: () -> Unit
+
+ override fun bind(holder: Holder) {
+ holder.view.setOnClickListener {
+ listener.invoke()
+ }
+
+ holder.title.text = title
+ holder.title.setTextColor(titleColor)
+
+ holder.subTitle.setTextOrHide(subTitle)
+
+ if (iconRes != -1) {
+ holder.icon.isVisible = true
+ holder.icon.setImageResource(iconRes)
+ if (iconColor != -1) {
+ ImageViewCompat.setImageTintList(holder.icon, ColorStateList.valueOf(iconColor))
+ }
+ } else {
+ holder.icon.isVisible = false
+ }
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val title by bind(R.id.itemVerificationActionTitle)
+ val subTitle by bind(R.id.itemVerificationActionSubTitle)
+ val icon by bind(R.id.itemVerificationActionIcon)
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationBigImageItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationBigImageItem.kt
new file mode 100644
index 0000000000..5163f5e8a8
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationBigImageItem.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package im.vector.riotx.features.crypto.verification.epoxy
+
+import android.widget.ImageView
+import androidx.core.view.ViewCompat
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.VectorEpoxyHolder
+import im.vector.riotx.core.epoxy.VectorEpoxyModel
+
+/**
+ * A action for bottom sheet.
+ */
+@EpoxyModelClass(layout = R.layout.item_verification_big_image)
+abstract class BottomSheetVerificationBigImageItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ var imageRes: Int = 0
+
+ @EpoxyAttribute
+ var contentDescription: String? = null
+
+ override fun bind(holder: Holder) {
+ holder.image.setImageResource(imageRes)
+
+ if (contentDescription == null) {
+ ViewCompat.setImportantForAccessibility(holder.image, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO)
+ } else {
+ ViewCompat.setImportantForAccessibility(holder.image, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES)
+ holder.image.contentDescription = contentDescription
+ }
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val image by bind(R.id.itemVerificationBigImage)
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationDecimalCodeItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationDecimalCodeItem.kt
new file mode 100644
index 0000000000..8d08ef0ba7
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationDecimalCodeItem.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package im.vector.riotx.features.crypto.verification.epoxy
+
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.VectorEpoxyHolder
+import im.vector.riotx.core.epoxy.VectorEpoxyModel
+
+/**
+ * A action for bottom sheet.
+ */
+@EpoxyModelClass(layout = R.layout.item_verification_decimal_code)
+abstract class BottomSheetVerificationDecimalCodeItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ var code: CharSequence = ""
+
+ override fun bind(holder: Holder) {
+ holder.code.text = code
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val code by bind(R.id.itemVerificationDecimalCode)
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationEmojisItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationEmojisItem.kt
new file mode 100644
index 0000000000..6f75d91d8f
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationEmojisItem.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package im.vector.riotx.features.crypto.verification.epoxy
+
+import android.view.ViewGroup
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.VectorEpoxyHolder
+import im.vector.riotx.core.epoxy.VectorEpoxyModel
+
+/**
+ * A emoji list for bottom sheet.
+ */
+@EpoxyModelClass(layout = R.layout.item_verification_emojis)
+abstract class BottomSheetVerificationEmojisItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute lateinit var emojiRepresentation0: EmojiRepresentation
+ @EpoxyAttribute lateinit var emojiRepresentation1: EmojiRepresentation
+ @EpoxyAttribute lateinit var emojiRepresentation2: EmojiRepresentation
+ @EpoxyAttribute lateinit var emojiRepresentation3: EmojiRepresentation
+ @EpoxyAttribute lateinit var emojiRepresentation4: EmojiRepresentation
+ @EpoxyAttribute lateinit var emojiRepresentation5: EmojiRepresentation
+ @EpoxyAttribute lateinit var emojiRepresentation6: EmojiRepresentation
+
+ override fun bind(holder: Holder) {
+ holder.emoji0View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation0.emoji
+ holder.emoji0View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation0.nameResId)
+
+ holder.emoji1View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation1.emoji
+ holder.emoji1View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation1.nameResId)
+
+ holder.emoji2View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation2.emoji
+ holder.emoji2View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation2.nameResId)
+
+ holder.emoji3View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation3.emoji
+ holder.emoji3View.findViewById(R.id.item_emoji_name_tv)?.setText(emojiRepresentation3.nameResId)
+
+ holder.emoji4View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation4.emoji
+ holder.emoji4View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation4.nameResId)
+
+ holder.emoji5View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation5.emoji
+ holder.emoji5View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation5.nameResId)
+
+ holder.emoji6View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation6.emoji
+ holder.emoji6View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation6.nameResId)
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val emoji0View by bind(R.id.emoji0)
+ val emoji1View by bind(R.id.emoji1)
+ val emoji2View by bind(R.id.emoji2)
+ val emoji3View by bind(R.id.emoji3)
+ val emoji4View by bind(R.id.emoji4)
+ val emoji5View by bind(R.id.emoji5)
+ val emoji6View by bind(R.id.emoji6)
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationNoticeItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationNoticeItem.kt
new file mode 100644
index 0000000000..b5314d4869
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationNoticeItem.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package im.vector.riotx.features.crypto.verification.epoxy
+
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.VectorEpoxyHolder
+import im.vector.riotx.core.epoxy.VectorEpoxyModel
+
+/**
+ * A action for bottom sheet.
+ */
+@EpoxyModelClass(layout = R.layout.item_verification_notice)
+abstract class BottomSheetVerificationNoticeItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ var notice: CharSequence = ""
+
+ override fun bind(holder: Holder) {
+ holder.notice.text = notice
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val notice by bind(R.id.itemVerificationNoticeText)
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationWaitingItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationWaitingItem.kt
new file mode 100644
index 0000000000..2af5ef418f
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationWaitingItem.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package im.vector.riotx.features.crypto.verification.epoxy
+
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.VectorEpoxyHolder
+import im.vector.riotx.core.epoxy.VectorEpoxyModel
+
+/**
+ * A action for bottom sheet.
+ */
+@EpoxyModelClass(layout = R.layout.item_verification_waiting)
+abstract class BottomSheetVerificationWaitingItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ var title: CharSequence = ""
+
+ override fun bind(holder: Holder) {
+ holder.title.text = title
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val title by bind(R.id.itemVerificationWaitingTitle)
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestController.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestController.kt
new file mode 100644
index 0000000000..e14b6573f4
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestController.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotx.features.crypto.verification.request
+
+import androidx.core.text.toSpannable
+import com.airbnb.epoxy.EpoxyController
+import com.airbnb.mvrx.Loading
+import im.vector.riotx.R
+import im.vector.riotx.core.epoxy.dividerItem
+import im.vector.riotx.core.resources.ColorProvider
+import im.vector.riotx.core.resources.StringProvider
+import im.vector.riotx.core.utils.colorizeMatchingText
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
+import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
+import javax.inject.Inject
+
+class VerificationRequestController @Inject constructor(
+ private val stringProvider: StringProvider,
+ private val colorProvider: ColorProvider
+) : EpoxyController() {
+
+ var listener: Listener? = null
+
+ private var viewState: VerificationRequestViewState? = null
+
+ fun update(viewState: VerificationRequestViewState) {
+ this.viewState = viewState
+ requestModelBuild()
+ }
+
+ override fun buildModels() {
+ val state = viewState ?: return
+
+ val styledText = state.matrixItem.let {
+ stringProvider.getString(R.string.verification_request_notice, it.id)
+ .toSpannable()
+ .colorizeMatchingText(it.id, colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color))
+ }
+
+ bottomSheetVerificationNoticeItem {
+ id("notice")
+ notice(styledText)
+ }
+
+ dividerItem {
+ id("sep")
+ }
+
+ when (state.started) {
+ is Loading -> {
+ bottomSheetVerificationWaitingItem {
+ id("waiting")
+ title(stringProvider.getString(R.string.verification_request_waiting_for, state.matrixItem.getBestName()))
+ }
+ }
+ else -> {
+ bottomSheetVerificationActionItem {
+ id("start")
+ title(stringProvider.getString(R.string.start_verification))
+ titleColor(colorProvider.getColor(R.color.riotx_accent))
+ subTitle(stringProvider.getString(R.string.verification_request_start_notice))
+ iconRes(R.drawable.ic_arrow_right)
+ iconColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
+ listener { listener?.onClickOnVerificationStart() }
+ }
+ }
+ }
+ }
+
+ interface Listener {
+ fun onClickOnVerificationStart()
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestFragment.kt
new file mode 100644
index 0000000000..8250bd74b8
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestFragment.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.riotx.features.crypto.verification.request
+
+import android.os.Bundle
+import android.view.View
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.parentFragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.riotx.R
+import im.vector.riotx.core.extensions.cleanup
+import im.vector.riotx.core.extensions.configureWith
+import im.vector.riotx.core.platform.VectorBaseFragment
+import im.vector.riotx.features.crypto.verification.VerificationAction
+import im.vector.riotx.features.crypto.verification.VerificationBottomSheetViewModel
+import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
+import javax.inject.Inject
+
+class VerificationRequestFragment @Inject constructor(
+ val verificationRequestViewModelFactory: VerificationRequestViewModel.Factory,
+ val controller: VerificationRequestController
+) : VectorBaseFragment(), VerificationRequestController.Listener {
+
+ private val viewModel by fragmentViewModel(VerificationRequestViewModel::class)
+
+ private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
+
+ override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupRecyclerView()
+ }
+
+ override fun onDestroyView() {
+ bottomSheetVerificationRecyclerView.cleanup()
+ controller.listener = null
+ super.onDestroyView()
+ }
+
+ private fun setupRecyclerView() {
+ bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
+ controller.listener = this
+ }
+
+ override fun invalidate() = withState(viewModel) { state ->
+ controller.update(state)
+ }
+
+ override fun onClickOnVerificationStart() = withState(viewModel) { state ->
+ sharedViewModel.handle(VerificationAction.RequestVerificationByDM(state.matrixItem.id, state.roomId))
+ }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationRequestViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestViewModel.kt
similarity index 96%
rename from vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationRequestViewModel.kt
rename to vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestViewModel.kt
index b21ce4e3a5..6f2855a5bb 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationRequestViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/request/VerificationRequestViewModel.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package im.vector.riotx.features.crypto.verification
+package im.vector.riotx.features.crypto.verification.request
import com.airbnb.mvrx.*
import com.squareup.inject.assisted.Assisted
@@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.crypto.verification.PendingVerification
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.VectorViewModel
+import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
data class VerificationRequestViewState(
val roomId: String? = null,
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt
index 358a5f3f57..d0716bd047 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt
@@ -67,6 +67,6 @@ sealed class RoomDetailAction : VectorViewModelAction {
data class AcceptVerificationRequest(val transactionId: String, val otherUserId: String, val otherdDeviceId: String) : RoomDetailAction()
data class DeclineVerificationRequest(val transactionId: String, val otherUserId: String, val otherdDeviceId: String) : RoomDetailAction()
-
data class RequestVerification(val userId: String) : RoomDetailAction()
+ data class ResumeVerification(val transactionId: String, val otherUserId: String? = null, val otherdDeviceId: String? = null) : RoomDetailAction()
}
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt
index 14e9061c36..fe4d0ae1f7 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt
@@ -109,7 +109,7 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
companion object {
- private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS"
+ const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS"
fun newIntent(context: Context, roomDetailArgs: RoomDetailArgs): Intent {
return Intent(context, RoomDetailActivity::class.java).apply {
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index 7e6d73eea7..236dd19030 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -54,6 +54,7 @@ import com.airbnb.epoxy.OnModelBuildFinishedListener
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
+import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
@@ -74,6 +75,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageFileConten
import im.vector.matrix.android.api.session.room.model.message.MessageImageInfoContent
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
import im.vector.matrix.android.api.session.room.model.message.MessageType
+import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.api.session.room.timeline.Timeline
@@ -849,6 +851,15 @@ class RoomDetailFragment @Inject constructor(
data.transactionId
).show(parentFragmentManager, "REQ")
}
+ is RoomDetailAction.ResumeVerification -> {
+ val otherUserId = data.otherUserId ?: return
+ VerificationBottomSheet().apply {
+ arguments = Bundle().apply {
+ putParcelable(MvRx.KEY_ARG, VerificationBottomSheet.VerificationArgs(
+ otherUserId, data.transactionId, roomId = roomDetailArgs.roomId))
+ }
+ }.show(parentFragmentManager, "REQ")
+ }
}
}
}
@@ -998,6 +1009,9 @@ class RoomDetailFragment @Inject constructor(
}
override fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View) {
+ if (messageContent is MessageVerificationRequestContent) {
+ roomDetailViewModel.handle(RoomDetailAction.ResumeVerification(informationData.eventId))
+ }
}
override fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View): Boolean {
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt
index 9fb08c2efe..9ca1feae21 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt
@@ -61,6 +61,7 @@ import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.core.utils.subscribeLogError
import im.vector.riotx.features.command.CommandParser
import im.vector.riotx.features.command.ParsedCommand
+import im.vector.riotx.features.crypto.verification.supportedVerificationMethods
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
import im.vector.riotx.features.home.room.typing.TypingHelper
import im.vector.riotx.features.settings.VectorPreferences
@@ -187,6 +188,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
is RoomDetailAction.AcceptVerificationRequest -> handleAcceptVerification(action)
is RoomDetailAction.DeclineVerificationRequest -> handleDeclineVerification(action)
is RoomDetailAction.RequestVerification -> handleRequestVerification(action)
+ is RoomDetailAction.ResumeVerification -> handleResumeRequestVerification(action)
}
}
@@ -408,7 +410,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
popDraft()
}
is ParsedCommand.VerifyUser -> {
- session.getSasVerificationService().requestKeyVerificationInDMs(slashCommandResult.userId, room.roomId)
+ session.getSasVerificationService().requestKeyVerificationInDMs(supportedVerificationMethods, slashCommandResult.userId, room.roomId)
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled())
popDraft()
}
@@ -824,6 +826,18 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
_requestLiveData.postValue(LiveEvent(Success(action)))
}
+ private fun handleResumeRequestVerification(action: RoomDetailAction.ResumeVerification) {
+ // Check if this request is still active and handled by me
+ session.getSasVerificationService().getExistingVerificationRequestInRoom(room.roomId, action.transactionId)?.let {
+ if (it.handledByOtherSession) return
+ if (!it.isFinished) {
+ _requestLiveData.postValue(LiveEvent(Success(action.copy(
+ otherUserId = it.otherUserId
+ ))))
+ }
+ }
+ }
+
private fun observeSyncState() {
session.rx()
.liveSyncState()
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt
index 4827c825cb..fe05d032ea 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt
@@ -18,12 +18,8 @@ package im.vector.riotx.features.home.room.detail.readreceipts
import android.os.Bundle
import android.os.Parcelable
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
-import butterknife.ButterKnife
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.args
import im.vector.riotx.R
@@ -57,11 +53,7 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment() {
injector.inject(this)
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.bottom_sheet_generic_list_with_title, container, false)
- ButterKnife.bind(this, view)
- return view
- }
+ override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt
index ba772344e0..1336c61b68 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt
@@ -16,12 +16,8 @@
package im.vector.riotx.features.home.room.detail.timeline.action
import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
-import butterknife.ButterKnife
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
@@ -53,18 +49,12 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
injector.inject(this)
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.bottom_sheet_generic_list, container, false)
- ButterKnife.bind(this, view)
- return view
- }
+ override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
- recyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false)
- // Disable item animation
- recyclerView.itemAnimator = null
+ recyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true)
messageActionsEpoxyController.listener = this
}
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt
index 8aa7c8561c..bf3816a030 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt
@@ -16,12 +16,8 @@
package im.vector.riotx.features.home.room.detail.timeline.edithistory
import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
-import butterknife.ButterKnife
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@@ -57,11 +53,7 @@ class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() {
injector.inject(this)
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.bottom_sheet_generic_list_with_title, container, false)
- ButterKnife.bind(this, view)
- return view
- }
+ override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt
index 8fddc4c06a..47764edf93 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt
@@ -17,12 +17,8 @@
package im.vector.riotx.features.home.room.detail.timeline.reactions
import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
-import butterknife.ButterKnife
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@@ -54,11 +50,7 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment() {
injector.inject(this)
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.bottom_sheet_generic_list_with_title, container, false)
- ButterKnife.bind(this, view)
- return view
- }
+ override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt
index 1e775a934a..6148b3c725 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt
@@ -18,12 +18,8 @@ package im.vector.riotx.features.home.room.list.actions
import android.os.Bundle
import android.os.Parcelable
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
-import butterknife.ButterKnife
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
@@ -69,18 +65,12 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R
injector.inject(this)
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.bottom_sheet_generic_list, container, false)
- ButterKnife.bind(this, view)
- return view
- }
+ override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
- recyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false)
- // Disable item animation
- recyclerView.itemAnimator = null
+ recyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
roomListActionsEpoxyController.listener = this
}
diff --git a/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt b/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt
index 664ea79fd2..6d92d36d38 100644
--- a/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt
+++ b/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt
@@ -20,12 +20,12 @@ import android.os.Build
import android.os.Handler
import android.os.Looper
import android.view.View
+import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import com.tapadoo.alerter.Alerter
import com.tapadoo.alerter.OnHideAlertListener
import im.vector.riotx.R
-import im.vector.riotx.features.crypto.verification.SASVerificationActivity
import timber.log.Timber
import java.lang.ref.WeakReference
@@ -78,8 +78,7 @@ object PopupAlertManager {
setLightStatusBar()
}
}
-
- if (shouldIgnoreActivity(activity)) {
+ if (currentAlerter?.shouldBeDisplayedIn?.invoke(activity) == false) {
return
}
@@ -108,8 +107,6 @@ object PopupAlertManager {
}
}
- private fun shouldIgnoreActivity(activity: Activity) = activity is SASVerificationActivity
-
private fun displayNextIfPossible() {
val currentActivity = weakCurrentActivity?.get()
if (Alerter.isShowing || currentActivity == null) {
@@ -209,7 +206,13 @@ object PopupAlertManager {
})
.enableSwipeToDismiss()
.enableInfiniteDuration(true)
- .setBackgroundColorRes(alert.colorRes ?: R.color.notification_accent_color)
+ .apply {
+ if (alert.colorInt != null) {
+ setBackgroundColorInt(alert.colorInt!!)
+ } else {
+ setBackgroundColorRes(alert.colorRes ?: R.color.notification_accent_color)
+ }
+ }
.show()
}
@@ -229,7 +232,8 @@ object PopupAlertManager {
data class VectorAlert(val uid: String,
val title: String,
val description: String,
- @DrawableRes val iconId: Int?) {
+ @DrawableRes val iconId: Int?,
+ val shouldBeDisplayedIn: ((Activity) -> Boolean)? = null) {
data class Button(val title: String, val action: Runnable, val autoClose: Boolean)
@@ -250,5 +254,8 @@ object PopupAlertManager {
@ColorRes
var colorRes: Int? = null
+
+ @ColorInt
+ var colorInt: Int? = null
}
}
diff --git a/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutBottomSheetDialogFragment.kt
index 94c718466f..e1ef7bc07b 100644
--- a/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutBottomSheetDialogFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutBottomSheetDialogFragment.kt
@@ -20,7 +20,6 @@ import android.app.Activity
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
-import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
@@ -32,7 +31,6 @@ import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.transition.TransitionManager
import butterknife.BindView
-import butterknife.ButterKnife
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
@@ -210,11 +208,7 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment() {
})
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = inflater.inflate(R.layout.bottom_sheet_logout_and_backup, container, false)
- ButterKnife.bind(this, view)
- return view
- }
+ override fun getLayoutResId() = R.layout.bottom_sheet_logout_and_backup
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
diff --git a/vector/src/main/res/drawable/ic_camera.xml b/vector/src/main/res/drawable/ic_camera.xml
new file mode 100644
index 0000000000..af44a317b3
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_camera.xml
@@ -0,0 +1,22 @@
+
+
+
+
diff --git a/vector/src/main/res/drawable/ic_check_off.xml b/vector/src/main/res/drawable/ic_check_off.xml
new file mode 100644
index 0000000000..6faf291278
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_check_off.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/vector/src/main/res/drawable/ic_check_on.xml b/vector/src/main/res/drawable/ic_check_on.xml
new file mode 100644
index 0000000000..05439c4df4
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_check_on.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/vector/src/main/res/layout/bottom_sheet_verification.xml b/vector/src/main/res/layout/bottom_sheet_verification.xml
index 7293434f0d..4585865973 100644
--- a/vector/src/main/res/layout/bottom_sheet_verification.xml
+++ b/vector/src/main/res/layout/bottom_sheet_verification.xml
@@ -1,6 +1,7 @@
-
+ android:layout_height="wrap_content">
-
+
+
+
+
-
-
-
-
-
-
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="16dp"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textColor="?riotx_text_primary"
+ android:textSize="20sp"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/verificationRequestAvatar"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/verificationRequestAvatar"
+ app:layout_constraintTop_toTopOf="@+id/verificationRequestAvatar"
+ tools:text="@string/verification_verify_user" />
+ android:layout_marginTop="16dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/verificationRequestAvatar" />
+
+
-
diff --git a/vector/src/main/res/layout/bottom_sheet_verification_child_fragment.xml b/vector/src/main/res/layout/bottom_sheet_verification_child_fragment.xml
new file mode 100644
index 0000000000..7375e505c7
--- /dev/null
+++ b/vector/src/main/res/layout/bottom_sheet_verification_child_fragment.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/vector/src/main/res/layout/fragment_bottom_sas_verification_code.xml b/vector/src/main/res/layout/fragment_bottom_sas_verification_code.xml
deleted file mode 100644
index 871e28b536..0000000000
--- a/vector/src/main/res/layout/fragment_bottom_sas_verification_code.xml
+++ /dev/null
@@ -1,188 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_sas_verification_display_code.xml b/vector/src/main/res/layout/fragment_sas_verification_display_code.xml
deleted file mode 100644
index 2d3a3135cb..0000000000
--- a/vector/src/main/res/layout/fragment_sas_verification_display_code.xml
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_sas_verification_incoming_request.xml b/vector/src/main/res/layout/fragment_sas_verification_incoming_request.xml
deleted file mode 100644
index 67815d3e65..0000000000
--- a/vector/src/main/res/layout/fragment_sas_verification_incoming_request.xml
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_sas_verification_start.xml b/vector/src/main/res/layout/fragment_sas_verification_start.xml
deleted file mode 100644
index edc7e8f7e3..0000000000
--- a/vector/src/main/res/layout/fragment_sas_verification_start.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_sas_verification_verified.xml b/vector/src/main/res/layout/fragment_sas_verification_verified.xml
deleted file mode 100644
index 170f977620..0000000000
--- a/vector/src/main/res/layout/fragment_sas_verification_verified.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_verification_choose_method.xml b/vector/src/main/res/layout/fragment_verification_choose_method.xml
deleted file mode 100644
index 37b3c6e53a..0000000000
--- a/vector/src/main/res/layout/fragment_verification_choose_method.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_verification_conclusion.xml b/vector/src/main/res/layout/fragment_verification_conclusion.xml
deleted file mode 100644
index 0c5ab7e6c2..0000000000
--- a/vector/src/main/res/layout/fragment_verification_conclusion.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_verification_request.xml b/vector/src/main/res/layout/fragment_verification_request.xml
deleted file mode 100644
index 79c81eb399..0000000000
--- a/vector/src/main/res/layout/fragment_verification_request.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/vector/src/main/res/layout/item_verification_action.xml b/vector/src/main/res/layout/item_verification_action.xml
new file mode 100644
index 0000000000..a92379a2a6
--- /dev/null
+++ b/vector/src/main/res/layout/item_verification_action.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/item_verification_big_image.xml b/vector/src/main/res/layout/item_verification_big_image.xml
new file mode 100644
index 0000000000..9f33b6c03c
--- /dev/null
+++ b/vector/src/main/res/layout/item_verification_big_image.xml
@@ -0,0 +1,7 @@
+
+
diff --git a/vector/src/main/res/layout/item_verification_decimal_code.xml b/vector/src/main/res/layout/item_verification_decimal_code.xml
new file mode 100644
index 0000000000..e7e2c503cb
--- /dev/null
+++ b/vector/src/main/res/layout/item_verification_decimal_code.xml
@@ -0,0 +1,18 @@
+
+
diff --git a/vector/src/main/res/layout/item_verification_emojis.xml b/vector/src/main/res/layout/item_verification_emojis.xml
new file mode 100644
index 0000000000..4e05e6207d
--- /dev/null
+++ b/vector/src/main/res/layout/item_verification_emojis.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/item_verification_notice.xml b/vector/src/main/res/layout/item_verification_notice.xml
new file mode 100644
index 0000000000..bb495f88b1
--- /dev/null
+++ b/vector/src/main/res/layout/item_verification_notice.xml
@@ -0,0 +1,13 @@
+
+
diff --git a/vector/src/main/res/layout/item_verification_waiting.xml b/vector/src/main/res/layout/item_verification_waiting.xml
new file mode 100644
index 0000000000..bcf99e6894
--- /dev/null
+++ b/vector/src/main/res/layout/item_verification_waiting.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml
index 4eb286ceaa..444d5ceb92 100644
--- a/vector/src/main/res/values/strings_riotX.xml
+++ b/vector/src/main/res/values/strings_riotX.xml
@@ -35,18 +35,20 @@
You
- Verify by scanning
-
- Ask the other user to scan this code, or %s to scan theirs
-
- open your camera
+ Scan the code with the other user\'s device to securely verify each other
+ Scan their code
+ Can\'t scan
+ If you\'re not in person, compare emoji instead
+
+ Continue
Verify by Emoji
If you can’t scan the code above, verify by comparing a short, unique selection of emoji.
- QR code image
+ QR code image
- Verify %s
+ Verify %s
+ Verified %s
Waiting for %s…
For extra security, verify %s by checking a one-time code on both your devices.\n\nFor maximum security, do this in person.
Messages in this room are not end-to-end encrypted.
@@ -85,4 +87,12 @@
Message editor
+
+ For extra security, verify %s by checking a one-time code.
+ For maximum security, do this in person.
+
+ Compare the unique emoji, ensuring they appear in the same order.
+ Compare the code with the one displayed on the other user\'s screen.
+ Messages with this user are end-to-end encrypted and can\'t be read by third parties.
+