mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-18 20:29:10 +03:00
Attempt to give accessibility focus to the first item of the RecyclerView when the recycler view is updated (screen change), to improve screen reader behavior.
This commit is contained in:
parent
20fedc87fe
commit
7a65a51ee1
2 changed files with 113 additions and 2 deletions
|
@ -21,12 +21,18 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.giveAccessibilityFocus
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
|
@ -36,15 +42,26 @@ import im.vector.app.core.utils.registerForPermissionsResult
|
|||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SelfVerificationFragment : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
class SelfVerificationFragment : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
SelfVerificationController.InteractionListener {
|
||||
|
||||
@Inject lateinit var controller: SelfVerificationController
|
||||
|
||||
private var requestAccessibilityFocus: Boolean = false
|
||||
private val modelBuildListener: OnModelBuildFinishedListener = OnModelBuildFinishedListener {
|
||||
if (requestAccessibilityFocus) {
|
||||
// Do not use giveAccessibilityFocusOnce() here.
|
||||
views.bottomSheetVerificationRecyclerView.layoutManager?.findViewByPosition(0)?.giveAccessibilityFocus()
|
||||
requestAccessibilityFocus = false
|
||||
// Note: it does not work when the recycler view is displayed for the first time, because findViewByPosition(0) is null
|
||||
}
|
||||
}
|
||||
|
||||
private val viewModel by parentFragmentViewModel(SelfVerificationViewModel::class)
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
|
@ -58,17 +75,22 @@ class SelfVerificationFragment : VectorBaseFragment<BottomSheetVerificationChil
|
|||
|
||||
override fun onDestroyView() {
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.removeModelBuildListener(modelBuildListener)
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.addModelBuildListener(modelBuildListener)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
// Timber.w("VALR: invalidate with State: ${state.pendingRequest}")
|
||||
if (state.isNewScreen()) {
|
||||
requestAccessibilityFocus = true
|
||||
}
|
||||
controller.update(state)
|
||||
}
|
||||
|
||||
|
@ -176,4 +198,41 @@ class SelfVerificationFragment : VectorBaseFragment<BottomSheetVerificationChil
|
|||
override fun declineRequest() {
|
||||
viewModel.handle(VerificationAction.CancelPendingVerification)
|
||||
}
|
||||
|
||||
private var currentScreenIndex = -1
|
||||
|
||||
private fun SelfVerificationViewState.isNewScreen(): Boolean {
|
||||
val newIndex = toScreenIndex()
|
||||
if (currentScreenIndex == newIndex) {
|
||||
return false
|
||||
}
|
||||
currentScreenIndex = newIndex
|
||||
return true
|
||||
}
|
||||
|
||||
private fun SelfVerificationViewState.toScreenIndex(): Int {
|
||||
return if (activeAction !is UserAction.None) {
|
||||
when (activeAction) {
|
||||
UserAction.ConfirmCancel -> 30
|
||||
UserAction.None -> 31
|
||||
}
|
||||
} else {
|
||||
when (pendingRequest) {
|
||||
is Fail -> 0
|
||||
is Loading -> 1
|
||||
is Success -> when (pendingRequest.invoke().state) {
|
||||
EVerificationState.WaitingForReady -> 10
|
||||
EVerificationState.Requested -> 11
|
||||
EVerificationState.Ready -> 12
|
||||
EVerificationState.Started -> 13
|
||||
EVerificationState.WeStarted -> 14
|
||||
EVerificationState.WaitingForDone -> 15
|
||||
EVerificationState.Done -> 16
|
||||
EVerificationState.Cancelled -> 17
|
||||
EVerificationState.HandledByOtherSession -> 18
|
||||
}
|
||||
Uninitialized -> 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,12 +21,18 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.giveAccessibilityFocus
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
|
@ -36,6 +42,7 @@ import im.vector.app.core.utils.registerForPermissionsResult
|
|||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -45,6 +52,16 @@ class UserVerificationFragment : VectorBaseFragment<BottomSheetVerificationChild
|
|||
|
||||
@Inject lateinit var controller: UserVerificationController
|
||||
|
||||
private var requestAccessibilityFocus: Boolean = false
|
||||
private val modelBuildListener: OnModelBuildFinishedListener = OnModelBuildFinishedListener {
|
||||
if (requestAccessibilityFocus) {
|
||||
// Do not use giveAccessibilityFocusOnce() here.
|
||||
views.bottomSheetVerificationRecyclerView.layoutManager?.findViewByPosition(0)?.giveAccessibilityFocus()
|
||||
requestAccessibilityFocus = false
|
||||
// Note: it does not work when the recycler view is displayed for the first time, because findViewByPosition(0) is null
|
||||
}
|
||||
}
|
||||
|
||||
private val viewModel by parentFragmentViewModel(UserVerificationViewModel::class)
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
|
@ -58,17 +75,22 @@ class UserVerificationFragment : VectorBaseFragment<BottomSheetVerificationChild
|
|||
|
||||
override fun onDestroyView() {
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.removeModelBuildListener(modelBuildListener)
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.addModelBuildListener(modelBuildListener)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
// Timber.w("VALR: invalidate with State: ${state.pendingRequest}")
|
||||
if (state.isNewScreen()) {
|
||||
requestAccessibilityFocus = true
|
||||
}
|
||||
controller.update(state)
|
||||
}
|
||||
|
||||
|
@ -142,10 +164,40 @@ class UserVerificationFragment : VectorBaseFragment<BottomSheetVerificationChild
|
|||
}
|
||||
|
||||
override fun onUserDeniesQrCodeScanned() {
|
||||
viewModel.handle(VerificationAction.OtherUserDidNotScanned)
|
||||
viewModel.handle(VerificationAction.OtherUserDidNotScanned)
|
||||
}
|
||||
|
||||
override fun onUserConfirmsQrCodeScanned() {
|
||||
viewModel.handle(VerificationAction.OtherUserScannedSuccessfully)
|
||||
}
|
||||
|
||||
private var currentScreenIndex = -1
|
||||
|
||||
private fun UserVerificationViewState.isNewScreen(): Boolean {
|
||||
val newIndex = toScreenIndex()
|
||||
if (currentScreenIndex == newIndex) {
|
||||
return false
|
||||
}
|
||||
currentScreenIndex = newIndex
|
||||
return true
|
||||
}
|
||||
|
||||
private fun UserVerificationViewState.toScreenIndex(): Int {
|
||||
return when (pendingRequest) {
|
||||
is Fail -> 0
|
||||
is Loading -> 1
|
||||
is Success -> when (pendingRequest.invoke().state) {
|
||||
EVerificationState.WaitingForReady -> 10
|
||||
EVerificationState.Requested -> 11
|
||||
EVerificationState.Ready -> 12
|
||||
EVerificationState.Started -> 13
|
||||
EVerificationState.WeStarted -> 14
|
||||
EVerificationState.WaitingForDone -> 15
|
||||
EVerificationState.Done -> 16
|
||||
EVerificationState.Cancelled -> 17
|
||||
EVerificationState.HandledByOtherSession -> 18
|
||||
}
|
||||
Uninitialized -> 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue