mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 18:35:40 +03:00
Basic Incoming request toast + cleaning
This commit is contained in:
parent
8400ab6efe
commit
8749e49e80
25 changed files with 189 additions and 1355 deletions
|
@ -44,6 +44,7 @@ interface SasVerificationService {
|
|||
|
||||
fun getExistingVerificationRequest(otherUser: String, tid: String?): PendingVerificationRequest?
|
||||
|
||||
fun getExistingVerificationRequestInRoom(roomId: String, tid: String?): PendingVerificationRequest?
|
||||
/**
|
||||
* Shortcut for KeyVerificationStart.VERIF_METHOD_SAS
|
||||
* @see beginKeyVerification
|
||||
|
|
|
@ -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<MessageRelationContent>()?.relatesTo?.eventId?.let {
|
||||
transactionsHandledByOtherDevice.remove(it)
|
||||
params.sasVerificationService.onRoomRequestHandledByOtherDevice(event)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -216,7 +216,20 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onRoomRequestReceived(event: Event) {
|
||||
fun onRoomRequestHandledByOtherDevice(event: Event) {
|
||||
val requestInfo = event.getClearContent().toModel<MessageRelationContent>()
|
||||
?: 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<MessageVerificationRequestContent>()
|
||||
?: return
|
||||
|
@ -245,6 +258,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
|
||||
)
|
||||
|
@ -647,6 +661,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<VerificationTransaction>? {
|
||||
synchronized(txMap) {
|
||||
return txMap[otherUser]?.values
|
||||
|
@ -723,6 +747,7 @@ internal class DefaultSasVerificationService @Inject constructor(
|
|||
val verificationRequest = PendingVerificationRequest(
|
||||
ageLocalTs = System.currentTimeMillis(),
|
||||
isIncoming = false,
|
||||
roomId = roomId,
|
||||
localID = localID,
|
||||
otherUserId = userId
|
||||
)
|
||||
|
|
|
@ -27,11 +27,13 @@ data class PendingVerificationRequest(
|
|||
val isIncoming: Boolean = false,
|
||||
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
|
||||
|
||||
) {
|
||||
|
||||
|
|
|
@ -47,9 +47,6 @@
|
|||
android:label="@string/title_activity_settings"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name=".features.media.VideoMediaViewerActivity" />
|
||||
<activity
|
||||
android:name=".features.crypto.verification.SASVerificationActivity"
|
||||
android:label="@string/title_activity_verify_device" />
|
||||
<activity
|
||||
android:name=".features.crypto.keysbackup.restore.KeysBackupRestoreActivity"
|
||||
android:label="@string/title_activity_keys_backup_setup" />
|
||||
|
|
|
@ -234,31 +234,6 @@ interface FragmentModule {
|
|||
@FragmentKey(VectorSettingsIgnoredUsersFragment::class)
|
||||
fun bindVectorSettingsIgnoredUsersFragment(fragment: VectorSettingsIgnoredUsersFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -101,10 +101,12 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
private lateinit var configurationViewModel: ConfigurationViewModel
|
||||
private lateinit var sessionListener: SessionListener
|
||||
protected lateinit var bugReporter: BugReporter
|
||||
lateinit var rageShake: RageShake
|
||||
private 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
|
||||
?: "")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<RoomDetailArgs>(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}"
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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<TextView>(R.id.item_emoji_tv).text = emojiRepresentation.emoji
|
||||
emoji0View.findViewById<TextView>(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
|
||||
}
|
||||
1 -> {
|
||||
emoji1View.findViewById<TextView>(R.id.item_emoji_tv).text = emojiRepresentation.emoji
|
||||
emoji1View.findViewById<TextView>(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
|
||||
}
|
||||
2 -> {
|
||||
emoji2View.findViewById<TextView>(R.id.item_emoji_tv).text = emojiRepresentation.emoji
|
||||
emoji2View.findViewById<TextView>(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
|
||||
}
|
||||
3 -> {
|
||||
emoji3View.findViewById<TextView>(R.id.item_emoji_tv).text = emojiRepresentation.emoji
|
||||
emoji3View.findViewById<TextView>(R.id.item_emoji_name_tv)?.setText(emojiRepresentation.nameResId)
|
||||
}
|
||||
4 -> {
|
||||
emoji4View.findViewById<TextView>(R.id.item_emoji_tv).text = emojiRepresentation.emoji
|
||||
emoji4View.findViewById<TextView>(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
|
||||
}
|
||||
5 -> {
|
||||
emoji5View.findViewById<TextView>(R.id.item_emoji_tv).text = emojiRepresentation.emoji
|
||||
emoji5View.findViewById<TextView>(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId)
|
||||
}
|
||||
6 -> {
|
||||
emoji6View.findViewById<TextView>(R.id.item_emoji_tv).text = emojiRepresentation.emoji
|
||||
emoji6View.findViewById<TextView>(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()
|
||||
}
|
||||
}
|
|
@ -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<MXDeviceInfo>() {
|
||||
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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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<SasVerificationTxState> = MutableLiveData()
|
||||
|
||||
init {
|
||||
// Force a first observe
|
||||
transactionState.value = null
|
||||
}
|
||||
|
||||
private var _navigateEvent: MutableLiveData<LiveEvent<String>> = MutableLiveData()
|
||||
val navigateEvent: LiveData<LiveEvent<String>>
|
||||
get() = _navigateEvent
|
||||
|
||||
var loadingLiveEvent: MutableLiveData<Int> = 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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -849,6 +849,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 +1007,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 {
|
||||
|
|
|
@ -187,6 +187,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -824,6 +825,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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:colorBackground">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_emoji_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@string/sas_emoji_description" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_emoji_description_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:text="@string/sas_security_advise"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_emoji_description" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_decimal_code"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/sas_emoji_grid"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/sas_emoji_grid"
|
||||
tools:text="1234-4320-3905"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/sas_emoji_grid"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:visibility="invisible"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sas_emoji_description_2"
|
||||
tools:visibility="visible">
|
||||
|
||||
<include
|
||||
android:id="@+id/emoji0"
|
||||
layout="@layout/item_emoji_verif" />
|
||||
|
||||
<include
|
||||
android:id="@+id/emoji1"
|
||||
layout="@layout/item_emoji_verif" />
|
||||
|
||||
<include
|
||||
android:id="@+id/emoji2"
|
||||
layout="@layout/item_emoji_verif" />
|
||||
|
||||
<include
|
||||
android:id="@+id/emoji3"
|
||||
layout="@layout/item_emoji_verif" />
|
||||
|
||||
<include
|
||||
android:id="@+id/emoji4"
|
||||
layout="@layout/item_emoji_verif" />
|
||||
|
||||
<include
|
||||
android:id="@+id/emoji5"
|
||||
layout="@layout/item_emoji_verif" />
|
||||
|
||||
<include
|
||||
android:id="@+id/emoji6"
|
||||
layout="@layout/item_emoji_verif" />
|
||||
|
||||
<androidx.constraintlayout.helper.widget.Flow
|
||||
android:id="@+id/sas_emoji_grid_flow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="emoji0,emoji1,emoji2,emoji3,emoji4,emoji5,emoji6"
|
||||
app:flow_horizontalBias="0.5"
|
||||
app:flow_horizontalGap="16dp"
|
||||
app:flow_horizontalStyle="packed"
|
||||
app:flow_verticalBias="0"
|
||||
app:flow_verticalGap="8dp"
|
||||
app:flow_wrapMode="chain"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_request_continue_button"
|
||||
style="@style/VectorButtonStyle"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:minWidth="160dp"
|
||||
android:text="@string/_continue"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sas_emoji_grid" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_request_cancel_button"
|
||||
style="@style/VectorButtonStyleText"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:text="@string/cancel"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sas_request_continue_button"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sas_emoji_grid" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
|
@ -1,132 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_incoming_request_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/sas_incoming_request_title"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/sas_incoming_request_user_avatar"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sas_incoming_request_title"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_incoming_request_user_display_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_incoming_request_user_avatar"
|
||||
tools:text="User name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_incoming_request_user_id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_incoming_request_user_display_name"
|
||||
tools:text="\@foo:matrix.org" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_incoming_request_user_device"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_incoming_request_user_id"
|
||||
tools:text="Device: Mobile" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_incoming_request_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:text="@string/sas_incoming_request_description"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_incoming_request_user_device" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_incoming_request_description_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:text="@string/sas_incoming_request_description_2"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_incoming_request_description" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_request_continue_button"
|
||||
style="@style/VectorButtonStyle"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin_big"
|
||||
android:layout_marginEnd="@dimen/layout_vertical_margin"
|
||||
android:layout_marginRight="@dimen/layout_vertical_margin"
|
||||
android:layout_marginBottom="@dimen/layout_vertical_margin"
|
||||
android:minWidth="160dp"
|
||||
android:text="@string/_continue"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sas_incoming_request_description_2" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_request_cancel_button"
|
||||
style="@style/VectorButtonStyleText"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginEnd="@dimen/layout_vertical_margin"
|
||||
android:layout_marginRight="@dimen/layout_vertical_margin"
|
||||
android:text="@string/cancel"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sas_request_continue_button"
|
||||
app:layout_constraintTop_toTopOf="@+id/sas_request_continue_button" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
|
@ -1,89 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_verification_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/sas_verify_title"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_verification_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/sas_security_advise"
|
||||
android:textColor="?riotx_text_secondary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_cancel_button"
|
||||
style="@style/VectorButtonStyleText"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:text="@string/cancel" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginRight="@dimen/layout_horizontal_margin">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_start_button"
|
||||
style="@style/VectorButtonStyle"
|
||||
android:minWidth="160dp"
|
||||
android:text="@string/sas_verify_start_button_title" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/sas_start_button_loading"
|
||||
android:layout_width="19dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_legacy_verification"
|
||||
style="@style/VectorButtonStyleText"
|
||||
android:layout_gravity="end"
|
||||
android:layout_margin="@dimen/layout_horizontal_margin"
|
||||
android:text="@string/sas_legacy_verification_button_title"
|
||||
android:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_verifying_keys"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/sas_verifying_keys"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
|
@ -1,69 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:colorBackground">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_verification_verified_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/sas_verified"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_verification_verified_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:text="@string/sas_verified_successful"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_verification_verified_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sas_verification_verified_description_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/layout_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:text="@string/sas_verified_successful_description"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sas_verification_verified_description" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sas_verification_verified_done_button"
|
||||
style="@style/VectorButtonStyle"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin_big"
|
||||
android:layout_marginEnd="@dimen/layout_vertical_margin"
|
||||
android:layout_marginRight="@dimen/layout_vertical_margin"
|
||||
android:layout_marginBottom="@dimen/layout_vertical_margin"
|
||||
android:minWidth="160dp"
|
||||
android:text="@string/sas_got_it"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sas_verification_verified_description_2" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
Loading…
Reference in a new issue