diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt new file mode 100644 index 0000000000..ce25af5fcd --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.crypto.verification.choose + +import com.airbnb.epoxy.EpoxyController +import im.vector.riotx.R +import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetSeparatorItem +import im.vector.riotx.core.resources.ColorProvider +import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem +import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem +import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem +import javax.inject.Inject + +class VerificationChooseMethodController @Inject constructor( + private val stringProvider: StringProvider, + private val colorProvider: ColorProvider +) : EpoxyController() { + + var listener: Listener? = null + + private var viewState: VerificationChooseMethodViewState? = null + + init { + // We are requesting a model build directly as the first build of epoxy is on the main thread. + // It avoids to build the whole list on the main thread. + requestModelBuild() + } + + fun update(viewState: VerificationChooseMethodViewState) { + this.viewState = viewState + requestModelBuild() + } + + override fun buildModels() { + val state = viewState ?: return + + if (state.QRModeAvailable) { + bottomSheetVerificationNoticeItem { + id("notice") + notice(stringProvider.getString(R.string.verification_scan_notice)) + } + + // TODO Generate the QR code + bottomSheetVerificationBigImageItem { + id("qr") + imageRes(R.drawable.riotx_logo) + } + + bottomSheetSeparatorItem { + id("sep0") + } + + bottomSheetVerificationActionItem { + id("openCamera") + title(stringProvider.getString(R.string.verification_scan_their_code)) + titleColor(colorProvider.getColor(R.color.riotx_accent)) + iconRes(R.drawable.ic_camera) + iconColor(colorProvider.getColor(R.color.riotx_accent)) + listener { listener?.openCamera() } + } + + bottomSheetSeparatorItem { + id("sep1") + } + + bottomSheetVerificationActionItem { + id("openEmoji") + title(stringProvider.getString(R.string.verification_scan_emoji_title)) + titleColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)) + subTitle(stringProvider.getString(R.string.verification_scan_emoji_subtitle)) + iconRes(R.drawable.ic_arrow_right) + iconColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)) + listener { listener?.doVerifyBySas() } + } + } else if (state.SASModeAvailable) { + bottomSheetVerificationActionItem { + id("openEmoji") + title(stringProvider.getString(R.string.verification_no_scan_emoji_title)) + titleColor(colorProvider.getColor(R.color.riotx_accent)) + iconRes(R.drawable.ic_arrow_right) + iconColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)) + listener { listener?.doVerifyBySas() } + } + } + } + + interface Listener { + fun openCamera() + fun doVerifyBySas() + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt index b50d967d1a..b782afca39 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt @@ -15,56 +15,59 @@ */ package im.vector.riotx.features.crypto.verification.choose -import android.text.style.ClickableSpan +import android.os.Bundle import android.view.View -import androidx.core.text.toSpannable -import androidx.core.view.isVisible -import butterknife.OnClick import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.riotx.R +import im.vector.riotx.core.extensions.cleanup +import im.vector.riotx.core.extensions.configureWith import im.vector.riotx.core.platform.VectorBaseFragment -import im.vector.riotx.core.utils.tappableMatchingText import im.vector.riotx.features.crypto.verification.VerificationAction import im.vector.riotx.features.crypto.verification.VerificationBottomSheetViewModel -import kotlinx.android.synthetic.main.fragment_verification_choose_method.* +import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* import javax.inject.Inject class VerificationChooseMethodFragment @Inject constructor( - val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory -) : VectorBaseFragment() { - - override fun getLayoutResId() = R.layout.fragment_verification_choose_method - - private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) + val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory, + val controller: VerificationChooseMethodController +) : VectorBaseFragment(), VerificationChooseMethodController.Listener { private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class) - override fun invalidate() = withState(viewModel) { state -> - if (state.QRModeAvailable) { - val cSpan = object : ClickableSpan() { - override fun onClick(widget: View) { - } - } - val openLink = getString(R.string.verify_open_camera_link) - val descCharSequence = - getString(R.string.verify_by_scanning_description, openLink) - .toSpannable() - .tappableMatchingText(openLink, cSpan) - verifyQRDescription.text = descCharSequence - verifyQRGroup.isVisible = true - } else { - verifyQRGroup.isVisible = false - } + private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) - verifyEmojiGroup.isVisible = state.SASMOdeAvailable + override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupRecyclerView() } - @OnClick(R.id.verificationByEmojiButton) - fun doVerifyBySas() = withState(sharedViewModel) { + override fun onDestroyView() { + bottomSheetVerificationRecyclerView.cleanup() + controller.listener = null + super.onDestroyView() + } + + private fun setupRecyclerView() { + bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + controller.listener = this + } + + override fun invalidate() = withState(viewModel) { state -> + controller.update(state) + } + + override fun doVerifyBySas() = withState(sharedViewModel) { sharedViewModel.handle(VerificationAction.StartSASVerification( it.otherUserMxItem?.id ?: "", it.pendingRequest?.transactionId ?: "")) } + + override fun openCamera() { + // TODO + } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt index 5d9fe18ab3..f5cf1676ba 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt @@ -35,7 +35,7 @@ data class VerificationChooseMethodViewState( val otherUserId: String = "", val transactionId: String = "", val QRModeAvailable: Boolean = false, - val SASMOdeAvailable: Boolean = false + val SASModeAvailable: Boolean = false ) : MvRxState class VerificationChooseMethodViewModel @AssistedInject constructor( @@ -57,7 +57,7 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( setState { copy( QRModeAvailable = qrAvailable, - SASMOdeAvailable = emojiAvailable + SASModeAvailable = emojiAvailable ) } } @@ -94,7 +94,7 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( return VerificationChooseMethodViewState(otherUserId = args.otherUserId, transactionId = args.verificationId ?: "", QRModeAvailable = qrAvailable, - SASMOdeAvailable = emojiAvailable + SASModeAvailable = emojiAvailable ) } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationActionItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationActionItem.kt index 2d3214d46e..a6b3459701 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationActionItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationActionItem.kt @@ -45,7 +45,7 @@ abstract class BottomSheetVerificationActionItem : VectorEpoxyModel Unit @@ -63,7 +63,9 @@ abstract class BottomSheetVerificationActionItem : VectorEpoxyModel + + + diff --git a/vector/src/main/res/layout/fragment_verification_choose_method.xml b/vector/src/main/res/layout/fragment_verification_choose_method.xml deleted file mode 100644 index 37b3c6e53a..0000000000 --- a/vector/src/main/res/layout/fragment_verification_choose_method.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_verification_conclusion.xml b/vector/src/main/res/layout/fragment_verification_conclusion.xml deleted file mode 100644 index 0c5ab7e6c2..0000000000 --- a/vector/src/main/res/layout/fragment_verification_conclusion.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index 3a8eae2396..444d5ceb92 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -35,16 +35,17 @@ You - Verify by scanning - - Ask the other user to scan this code, or %s to scan theirs - - open your camera + Scan the code with the other user\'s device to securely verify each other + Scan their code + Can\'t scan + If you\'re not in person, compare emoji instead + + Continue Verify by Emoji If you can’t scan the code above, verify by comparing a short, unique selection of emoji. - QR code image + QR code image Verify %s Verified %s