1
0
mirror of https://github.com/vector-im/riotX-android synced 2025-10-06 00:02:48 +02:00

Compare commits

...

9 Commits

Author SHA1 Message Date
Ahmed Radhouane Belkilani
ade833da21 #4025
- code quality line length limit.

Signed-off-by: Ahmed Radhouane Belkilani <arbelkilani@gmail.com>
2022-02-23 11:59:45 +01:00
Ahmed Radhouane Belkilani
c64a786446 #4025
- Add annotation @CallSuper to ensure calling super method.
- Remove unused fragment class VerificationCancelFragment.

Signed-off-by: Ahmed Radhouane Belkilani <arbelkilani@gmail.com>
2022-02-23 11:29:53 +01:00
Ahmed Radhouane Belkilani
279e45dbc4 #4025
- update changelog file.

Signed-off-by: Ahmed Radhouane Belkilani <arbelkilani@gmail.com>
2022-02-23 11:29:53 +01:00
Ahmed Radhouane Belkilani
7ba377e84d After Fixing gradle command issues.
Pushing format code.
2022-02-23 11:29:52 +01:00
Ahmed Radhouane Belkilani
764b8ae897 - Fix after Ktlint and check suite reports.
- Change AppCompatButton to Button.
2022-02-23 11:29:52 +01:00
Ahmed Radhouane Belkilani
79f6e64a76 - Fix after Ktlint and check suite reports. 2022-02-23 11:29:51 +01:00
Ahmed Radhouane Belkilani
d3423bdf2b - Fix after run code inspect. 2022-02-23 11:29:50 +01:00
Ahmed Radhouane Belkilani
3fceaa3bb4 - adding changelog file. 2022-02-23 11:29:50 +01:00
Ahmed Radhouane Belkilani
91c47b0ff9 - enable canceling verification bottom sheets on clicking outside.
- change Verification cancel bottom sheet to a dialog (not cancelable)
  in order to ensure that user is aware of canceling verification process.
  - in resources add space before interrogation mark.
2022-02-23 11:29:49 +01:00
12 changed files with 499 additions and 87 deletions

1
changelog.d/4025.bugfix Normal file
View File

@@ -0,0 +1 @@
Can't get out of a verification bottom sheet dialog.

View File

@@ -17,6 +17,7 @@
package im.vector.app.core.di
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import dagger.Binds
@@ -40,7 +41,7 @@ import im.vector.app.features.crypto.recover.BootstrapSaveRecoveryKeyFragment
import im.vector.app.features.crypto.recover.BootstrapSetupRecoveryKeyFragment
import im.vector.app.features.crypto.recover.BootstrapWaitingFragment
import im.vector.app.features.crypto.verification.QuadSLoadingFragment
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
import im.vector.app.features.crypto.verification.cancel.VerificationCancelDialogFragment
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodFragment
import im.vector.app.features.crypto.verification.conclusion.VerificationConclusionFragment
@@ -633,6 +634,11 @@ interface FragmentModule {
@FragmentKey(VerificationChooseMethodFragment::class)
fun bindVerificationChooseMethodFragment(fragment: VerificationChooseMethodFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VerificationCancelDialogFragment::class)
fun bindVerificationCancelDialogFragment(fragment: VerificationCancelDialogFragment): DialogFragment
@Binds
@IntoMap
@FragmentKey(VerificationEmojiCodeFragment::class)
@@ -653,11 +659,6 @@ interface FragmentModule {
@FragmentKey(VerificationConclusionFragment::class)
fun bindVerificationConclusionFragment(fragment: VerificationConclusionFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VerificationCancelFragment::class)
fun bindVerificationCancelFragment(fragment: VerificationCancelFragment): Fragment
@Binds
@IntoMap
@FragmentKey(QuadSLoadingFragment::class)

View File

@@ -32,6 +32,7 @@ import im.vector.app.features.crypto.keysbackup.settings.KeysBackupSettingsViewM
import im.vector.app.features.crypto.quads.SharedSecureStorageViewModel
import im.vector.app.features.crypto.recover.BootstrapSharedViewModel
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import im.vector.app.features.crypto.verification.cancel.VerificationCancelViewModel
import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodViewModel
import im.vector.app.features.crypto.verification.emoji.VerificationEmojiCodeViewModel
import im.vector.app.features.devtools.RoomDevToolViewModel
@@ -505,6 +506,11 @@ interface MavericksViewModelModule {
@MavericksViewModelKey(VerificationChooseMethodViewModel::class)
fun verificationChooseMethodViewModelFactory(factory: VerificationChooseMethodViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
@Binds
@IntoMap
@MavericksViewModelKey(VerificationCancelViewModel::class)
fun verificationCancelViewModelFactory(factory: VerificationCancelViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
@Binds
@IntoMap
@MavericksViewModelKey(VerificationEmojiCodeViewModel::class)

View File

@@ -110,6 +110,12 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
resultListener?.onBottomSheetResult(bottomSheetResult, bottomSheetResultData)
}
@CallSuper
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
resultListener?.onBottomSheetResult(bottomSheetResult, bottomSheetResultData)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = getBinding(inflater, container)
return views.root

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2022 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.app.core.platform
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 androidx.annotation.CallSuper
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.airbnb.mvrx.MavericksView
import dagger.hilt.android.EntryPointAccessors
import im.vector.app.core.di.ActivityEntryPoint
import im.vector.app.core.extensions.toMvRxBundle
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.clicks
abstract class VectorBaseDialogFragment<VB : ViewBinding> : DialogFragment(), MavericksView {
/* ==========================================================================================
* View
* ========================================================================================== */
private var _binding: VB? = null
// This property is only valid between onCreateView and onDestroyView.
protected val views: VB
get() = _binding!!
abstract fun getBinding(inflater: LayoutInflater, container: ViewGroup?): VB
/* ==========================================================================================
* View model
* ========================================================================================== */
private lateinit var viewModelFactory: ViewModelProvider.Factory
protected val activityViewModelProvider
get() = ViewModelProvider(requireActivity(), viewModelFactory)
protected val fragmentViewModelProvider
get() = ViewModelProvider(this, viewModelFactory)
val vectorBaseActivity: VectorBaseActivity<*> by lazy {
activity as VectorBaseActivity<*>
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = getBinding(inflater, container)
return views.root
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.setLayout(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
}
}
@CallSuper
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
@CallSuper
override fun onDestroy() {
super.onDestroy()
}
override fun onAttach(context: Context) {
val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
viewModelFactory = activityEntryPoint.viewModelFactory()
super.onAttach(context)
}
override fun onStart() {
super.onStart()
postInvalidate()
}
protected fun setArguments(args: Parcelable? = null) {
arguments = args.toMvRxBundle()
}
/* ==========================================================================================
* Views
* ========================================================================================== */
protected fun View.debouncedClicks(onClicked: () -> Unit) {
clicks()
.onEach { onClicked() }
.launchIn(viewLifecycleOwner.lifecycleScope)
}
/* ==========================================================================================
* ViewEvents
* ========================================================================================== */
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
viewEvents
.stream()
.onEach {
observer(it)
}
.launchIn(viewLifecycleOwner.lifecycleScope)
}
}

View File

@@ -17,12 +17,14 @@ package im.vector.app.features.crypto.verification
import android.app.Activity
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.os.Parcelable
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.CallSuper
import androidx.fragment.app.Fragment
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@@ -37,7 +39,7 @@ import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetVerificationBinding
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
import im.vector.app.features.crypto.verification.cancel.VerificationCancelDialogFragment
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodFragment
import im.vector.app.features.crypto.verification.conclusion.VerificationConclusionFragment
@@ -71,7 +73,8 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
val verificationLocalId: String? = null,
val roomId: String? = null,
// Special mode where UX should show loading wheel until other session sends a request/tx
val selfVerificationMode: Boolean = false
val selfVerificationMode: Boolean = false,
val userTrustLevel: RoomEncryptionTrustLevel? = null
) : Parcelable
override val showExpanded = true
@@ -85,10 +88,6 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
return BottomSheetVerificationBinding.inflate(inflater, container, false)
}
init {
isCancelable = false
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -135,6 +134,15 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
}
}
@CallSuper
override fun onCancel(dialog: DialogInterface) {
viewModel.queryCancel()
withState(viewModel) { state ->
showCancelVerificationDialog(state)
}
super.onCancel(dialog)
}
private val secretStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
val result = activityResult.data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
@@ -196,7 +204,8 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
if (state.userWantsToCancel) {
views.otherUserNameText.text = getString(R.string.are_you_sure)
showFragment(VerificationCancelFragment::class)
dismiss()
showCancelVerificationDialog(state)
return@withState
}
@@ -357,6 +366,15 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
}
}
private fun showCancelVerificationDialog(state: VerificationBottomSheetViewState) {
VerificationCancelDialogFragment.newInstance(
VerificationArgs(
state.otherUserMxItem?.id ?: "",
state.pendingRequest.invoke()?.transactionId ?: state.transactionId,
userTrustLevel = state.userTrustLevel)
).show(vectorBaseActivity.supportFragmentManager, VerificationCancelDialogFragment::class.java.name)
}
companion object {
fun withArgs(roomId: String?, otherUserId: String, transactionId: String? = null): VerificationBottomSheet {
return VerificationBottomSheet().apply {

View File

@@ -34,6 +34,7 @@ import im.vector.app.core.resources.StringProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
@@ -79,7 +80,8 @@ data class VerificationBottomSheetViewState(
val userThinkItsNotHim: Boolean = false,
val quadSContainsSecrets: Boolean = true,
val quadSHasBeenReset: Boolean = false,
val hasAnyOtherSession: Boolean = false
val hasAnyOtherSession: Boolean = false,
val userTrustLevel: RoomEncryptionTrustLevel? = null
) : MavericksState {
constructor(args: VerificationBottomSheet.VerificationArgs) : this(
@@ -140,6 +142,8 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
it.deviceId != session.sessionParams.deviceId
}
val userTrustLevel = trustLevel(initialState, sasTx, qrTx)
setState {
copy(
otherUserMxItem = userItem?.toMatrixItem(),
@@ -150,7 +154,8 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
isMe = initialState.otherUserId == session.myUserId,
currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign(),
quadSContainsSecrets = session.sharedSecretStorageService.isRecoverySetup(),
hasAnyOtherSession = hasAnyOtherSession
hasAnyOtherSession = hasAnyOtherSession,
userTrustLevel = userTrustLevel
)
}
@@ -165,6 +170,23 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
}
}
private fun trustLevel(
state: VerificationBottomSheetViewState,
sas: SasVerificationTransaction?,
qr: QrCodeVerificationTransaction?): RoomEncryptionTrustLevel {
val userTrustLevel = if (state.isMe) {
if (sas?.state == VerificationTxState.Verified ||
qr?.state == VerificationTxState.Verified ||
state.verifiedFromPrivateKeys) RoomEncryptionTrustLevel.Trusted
else RoomEncryptionTrustLevel.Warning
} else {
if (sas?.state == VerificationTxState.Verified || qr?.state == VerificationTxState.Verified) {
RoomEncryptionTrustLevel.Trusted
} else RoomEncryptionTrustLevel.Warning
}
return userTrustLevel
}
override fun onCleared() {
session.cryptoService().verificationService().removeListener(this)
super.onCleared()

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2022 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.app.features.crypto.verification.cancel
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseDialogFragment
import im.vector.app.databinding.DialogVerificationCancelBinding
import im.vector.app.features.crypto.verification.VerificationBottomSheet
import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject
@AndroidEntryPoint
class VerificationCancelDialogFragment : VectorBaseDialogFragment<DialogVerificationCancelBinding>() {
companion object {
fun newInstance(args: VerificationBottomSheet.VerificationArgs): VerificationCancelDialogFragment {
return VerificationCancelDialogFragment().apply {
setArguments(args)
}
}
}
init {
isCancelable = false
}
@Inject
lateinit var avatarRenderer: AvatarRenderer
private val viewModel by fragmentViewModel(VerificationCancelViewModel::class)
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): DialogVerificationCancelBinding {
return DialogVerificationCancelBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
handleSkipAction()
}
override fun invalidate() = withState(viewModel) { state ->
state.userMxItem?.let { matrixItem ->
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
views.otherUserShield.render(state.userTrustLevel)
updateDialogContent(state, matrixItem)
handleContinueAction(state)
}
return@withState
}
private fun handleSkipAction() {
views.btnSkipAction.setOnClickListener {
viewModel.confirmCancel()
dismiss()
}
}
private fun handleContinueAction(state: VerificationCancelViewState) {
views.btnContinueAction.setOnClickListener {
VerificationBottomSheet.withArgs(
roomId = state.roomId,
otherUserId = state.otherUserId,
transactionId = state.transactionId
).show(parentFragmentManager, "REQ")
dismiss()
}
}
private fun updateDialogContent(state: VerificationCancelViewState, matrixItem: MatrixItem) {
if (state.isMe) {
if (state.currentDeviceCanCrossSign) {
views.dialogContent.text = getString(R.string.verify_cancel_self_verification_from_trusted)
} else {
views.dialogContent.text = getString(R.string.verify_cancel_self_verification_from_untrusted)
}
} else {
views.dialogContent.text = getString(R.string.verify_cancel_other, matrixItem.displayName, matrixItem.id)
}
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 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.app.features.crypto.verification.cancel
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import javax.inject.Inject
class VerificationCancelFragment @Inject constructor(
val controller: VerificationCancelController
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationCancelController.Listener {
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
}
override fun onDestroyView() {
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}
override fun invalidate() = withState(viewModel) { state ->
controller.update(state)
}
override fun onTapCancel() {
viewModel.confirmCancel()
}
override fun onTapContinue() {
viewModel.continueFromCancel()
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2022 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.app.features.crypto.verification.cancel
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.EntryPoints
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.SingletonEntryPoint
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.crypto.verification.VerificationBottomSheet
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem
data class VerificationCancelViewState(
val userMxItem: MatrixItem? = null,
val otherUserId: String,
val transactionId: String? = null,
val roomId: String? = null,
val userTrustLevel: RoomEncryptionTrustLevel? = null,
val isMe: Boolean = false,
val currentDeviceCanCrossSign: Boolean = false,
) : MavericksState
class VerificationCancelViewModel @AssistedInject constructor(
@Assisted initialState: VerificationCancelViewState,
private val session: Session
) : VectorViewModel<VerificationCancelViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener {
init {
session.cryptoService().verificationService().addListener(this)
}
override fun onCleared() {
session.cryptoService().verificationService().removeListener(this)
super.onCleared()
}
@AssistedFactory
interface Factory : MavericksAssistedViewModelFactory<VerificationCancelViewModel, VerificationCancelViewState> {
override fun create(initialState: VerificationCancelViewState): VerificationCancelViewModel
}
companion object : MavericksViewModelFactory<VerificationCancelViewModel, VerificationCancelViewState> by hiltMavericksViewModelFactory() {
override fun initialState(viewModelContext: ViewModelContext): VerificationCancelViewState {
val args = viewModelContext.args<VerificationBottomSheet.VerificationArgs>()
val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
val matrixItem = session.getUser(args.otherUserId)?.toMatrixItem()
return VerificationCancelViewState(
userMxItem = matrixItem,
otherUserId = args.otherUserId,
roomId = args.roomId,
transactionId = args.verificationId,
userTrustLevel = args.userTrustLevel,
isMe = args.otherUserId == session.myUserId,
currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign()
)
}
}
override fun handle(action: EmptyAction) {}
private fun cancelAllPendingVerifications(state: VerificationCancelViewState) {
session.cryptoService()
.verificationService().getExistingVerificationRequest(state.userMxItem?.id ?: "", state.transactionId)?.let {
session.cryptoService().verificationService().cancelVerificationRequest(it)
}
session.cryptoService()
.verificationService()
.getExistingTransaction(state.userMxItem?.id ?: "", state.transactionId ?: "")
?.cancel(CancelCode.User)
}
fun confirmCancel() = withState { state ->
cancelAllPendingVerifications(state)
}
}

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent"
android:layout_width="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="?colorSurface"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/otherUserAvatarImageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:adjustViewBounds="true"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@sample/user_round_avatars" />
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/otherUserShield"
android:layout_width="20dp"
android:layout_height="20dp"
app:layout_constraintCircle="@id/otherUserAvatarImageView"
app:layout_constraintCircleAngle="139"
app:layout_constraintCircleRadius="20dp"
tools:ignore="MissingConstraints" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/Widget.Vector.TextView.HeadlineMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/are_you_sure"
android:textColor="?vctr_content_primary"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/otherUserAvatarImageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/otherUserAvatarImageView"
app:layout_constraintTop_toTopOf="@id/otherUserAvatarImageView"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:layout_marginStart="20dp"
app:layout_constraintTop_toBottomOf="@id/otherUserAvatarImageView"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="parent"
android:textColor="?vctr_content_secondary"
style="@style/TextAppearance.Vector.Body"
tools:text="@string/verify_cancel_self_verification_from_untrusted"/>
<Button
android:id="@+id/btn_skip_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?colorError"
android:layout_marginTop="18dp"
android:layout_marginEnd="8dp"
android:padding="0dp"
android:background="@android:color/transparent"
app:layout_constraintEnd_toStartOf="@id/btn_continue_action"
app:layout_constraintTop_toBottomOf="@id/dialog_content"
android:text="@string/action_skip"/>
<Button
android:id="@+id/btn_continue_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?colorPrimary"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:padding="0dp"
app:layout_constraintTop_toTopOf="@id/btn_skip_action"
android:background="@android:color/transparent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/dialog_content"
android:text="@string/_continue"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -3022,8 +3022,8 @@
<string name="verify_new_session_was_not_me">This wasnt me</string>
<string name="verify_new_session_compromized">Your account may be compromised</string>
<string name="verify_cancel_self_verification_from_untrusted">If you cancel, you wont be able to read encrypted messages on this device, and other users wont trust it</string>
<string name="verify_cancel_self_verification_from_trusted">If you cancel, you wont be able to read encrypted messages on your new device, and other users wont trust it</string>
<string name="verify_cancel_self_verification_from_untrusted">If you cancel, you wont be able to read encrypted messages on this device, and other users wont trust it.</string>
<string name="verify_cancel_self_verification_from_trusted">If you cancel, you wont be able to read encrypted messages on your new device, and other users wont trust it.</string>
<string name="verify_cancel_other">You wont verify %1$s (%2$s) if you cancel now. Start again in their user profile.</string>
<string name="verify_not_me_self_verification">