Merge pull request #8410 from vector-im/feature/bma/fixCrashes

Fix crashes
This commit is contained in:
Benoit Marty 2023-05-11 14:51:33 +02:00 committed by GitHub
commit f9f341e0ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 92 additions and 111 deletions

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

@ -0,0 +1 @@
Fix crash when opening "Protect access" screen, and various other issue with `repeatOnLifecycle`

View File

@ -21,10 +21,9 @@ import android.text.Editable
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.autofill.HintConstants import androidx.autofill.HintConstants
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.withResumed
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import im.vector.app.core.platform.SimpleTextWatcher import im.vector.app.core.platform.SimpleTextWatcher
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -88,7 +87,7 @@ fun TextInputLayout.setOnImeDoneListener(action: () -> Unit) {
fun TextInputLayout.setOnFocusLostListener(lifecycleOwner: LifecycleOwner, action: () -> Unit) { fun TextInputLayout.setOnFocusLostListener(lifecycleOwner: LifecycleOwner, action: () -> Unit) {
editText().setOnFocusChangeListener { _, hasFocus -> editText().setOnFocusChangeListener { _, hasFocus ->
when (hasFocus) { when (hasFocus) {
false -> lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { action() } } false -> lifecycleOwner.lifecycleScope.launch { lifecycleOwner.withResumed { action() } }
else -> { else -> {
// do nothing // do nothing
} }

View File

@ -30,9 +30,8 @@ import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.withResumed
import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -402,7 +401,9 @@ class HomeActivity :
private fun handleStartRecoverySetup() { private fun handleStartRecoverySetup() {
// To avoid IllegalStateException in case the transaction was executed after onSaveInstanceState // To avoid IllegalStateException in case the transaction was executed after onSaveInstanceState
lifecycleScope.launch { lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) { navigator.open4SSetup(this@HomeActivity, SetupMode.NORMAL) } withResumed {
navigator.open4SSetup(this@HomeActivity, SetupMode.NORMAL)
}
} }
} }

View File

@ -47,9 +47,8 @@ import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.withResumed
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -1112,29 +1111,31 @@ class TimelineFragment :
private fun updateJumpToReadMarkerViewVisibility() { private fun updateJumpToReadMarkerViewVisibility() {
if (isThreadTimeLine()) return if (isThreadTimeLine()) return
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { withResumed {
val state = timelineViewModel.awaitState() viewLifecycleOwner.lifecycleScope.launch {
val showJumpToUnreadBanner = when (state.unreadState) { val state = timelineViewModel.awaitState()
UnreadState.Unknown, val showJumpToUnreadBanner = when (state.unreadState) {
UnreadState.HasNoUnread -> false UnreadState.Unknown,
is UnreadState.ReadMarkerNotLoaded -> true UnreadState.HasNoUnread -> false
is UnreadState.HasUnread -> { is UnreadState.ReadMarkerNotLoaded -> true
if (state.canShowJumpToReadMarker) { is UnreadState.HasUnread -> {
val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition() if (state.canShowJumpToReadMarker) {
val positionOfReadMarker = withContext(Dispatchers.Default) { val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition()
timelineEventController.getPositionOfReadMarker() val positionOfReadMarker = withContext(Dispatchers.Default) {
} timelineEventController.getPositionOfReadMarker()
if (positionOfReadMarker == null) { }
false if (positionOfReadMarker == null) {
false
} else {
positionOfReadMarker > lastVisibleItem
}
} else { } else {
positionOfReadMarker > lastVisibleItem false
} }
} else {
false
} }
} }
views.jumpToReadMarkerView.isVisible = showJumpToUnreadBanner
} }
views.jumpToReadMarkerView.isVisible = showJumpToUnreadBanner
} }
} }
} }
@ -1625,14 +1626,16 @@ class TimelineFragment :
override fun onRoomCreateLinkClicked(url: String) { override fun onRoomCreateLinkClicked(url: String) {
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { withResumed {
permalinkHandler viewLifecycleOwner.lifecycleScope.launch {
.launch(requireActivity(), url, object : NavigationInterceptor { permalinkHandler
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean { .launch(requireActivity(), url, object : NavigationInterceptor {
requireActivity().finish() override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean {
return false requireActivity().finish()
} return false
}) }
})
}
} }
} }
} }

View File

@ -26,9 +26,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -101,12 +99,10 @@ class LocationSharingFragment :
views.mapView.onCreate(savedInstanceState) views.mapView.onCreate(savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { views.mapView.initialize(
views.mapView.initialize( url = urlMapProvider.getMapUrl(),
url = urlMapProvider.getMapUrl(), locationTargetChangeListener = this@LocationSharingFragment
locationTargetChangeListener = this@LocationSharingFragment )
)
}
} }
initLocateButton() initLocateButton()

View File

@ -22,9 +22,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.mvrx.args import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
@ -81,9 +79,7 @@ class LocationPreviewFragment :
views.mapView.onCreate(savedInstanceState) views.mapView.onCreate(savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { views.mapView.initialize(urlMapProvider.getMapUrl())
views.mapView.initialize(urlMapProvider.getMapUrl())
}
} }
observeViewEvents() observeViewEvents()

View File

@ -16,9 +16,7 @@
package im.vector.app.features.settings package im.vector.app.features.settings
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -80,13 +78,13 @@ class VectorSettingsPinFragment :
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
updateBiometricPrefState(isPinCodeChecked = usePinCodePref.isChecked) updateBiometricPrefState(isPinCodeChecked = usePinCodePref.isChecked)
viewLifecycleOwner.lifecycleScope.launch {
refreshPinCodeStatus()
}
} }
override fun bindPref() { override fun bindPref() {
refreshPinCodeStatus()
usePinCodePref.setOnPreferenceChangeListener { _, value -> usePinCodePref.setOnPreferenceChangeListener { _, value ->
val isChecked = (value as? Boolean).orFalse() val isChecked = (value as? Boolean).orFalse()
updateBiometricPrefState(isPinCodeChecked = isChecked) updateBiometricPrefState(isPinCodeChecked = isChecked)
@ -130,38 +128,34 @@ class VectorSettingsPinFragment :
.onFailure { Timber.e(it) } .onFailure { Timber.e(it) }
} }
private fun refreshPinCodeStatus() { private suspend fun refreshPinCodeStatus() {
viewLifecycleOwner.lifecycleScope.launch { val hasPinCode = pinCodeStore.hasEncodedPin()
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { usePinCodePref.isChecked = hasPinCode
val hasPinCode = pinCodeStore.hasEncodedPin() usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
usePinCodePref.isChecked = hasPinCode if (hasPinCode) {
usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener { lifecycleScope.launch {
if (hasPinCode) { pinCodeStore.deletePinCode()
lifecycleScope.launch { refreshPinCodeStatus()
pinCodeStore.deletePinCode()
refreshPinCodeStatus()
}
} else {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.CREATE
)
}
true
}
changePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
if (hasPinCode) {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.MODIFY
)
}
true
} }
} else {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.CREATE
)
} }
true
}
changePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
if (hasPinCode) {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.MODIFY
)
}
true
} }
} }
@ -170,6 +164,6 @@ class VectorSettingsPinFragment :
} }
private val pinActivityResultLauncher = registerStartForActivityResult { private val pinActivityResultLauncher = registerStartForActivityResult {
refreshPinCodeStatus() // Nothing to do, refreshPinCodeStatus() will be called by `onResume`
} }
} }

View File

@ -27,9 +27,8 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.withResumed
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
@ -190,6 +189,10 @@ class VectorSettingsSecurityPrivacyFragment :
rawService rawService
.getElementWellknown(session.sessionParams) .getElementWellknown(session.sessionParams)
?.isE2EByDefault() == false ?.isE2EByDefault() == false
refreshXSigningStatus()
// My device name may have been updated
refreshMyDevice()
} }
} }
@ -288,19 +291,6 @@ class VectorSettingsSecurityPrivacyFragment :
true true
} }
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
refreshXSigningStatus()
}
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
// My device name may have been updated
refreshMyDevice()
}
}
secureBackupPreference.icon = activity?.let { secureBackupPreference.icon = activity?.let {
ThemeUtils.tintDrawable( ThemeUtils.tintDrawable(
it, it,
@ -429,16 +419,18 @@ class VectorSettingsSecurityPrivacyFragment :
private fun openPinCodePreferenceScreen() { private fun openPinCodePreferenceScreen() {
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { withResumed {
val hasPinCode = pinCodeStore.hasEncodedPin() viewLifecycleOwner.lifecycleScope.launch {
if (hasPinCode) { val hasPinCode = pinCodeStore.hasEncodedPin()
navigator.openPinCode( if (hasPinCode) {
requireContext(), navigator.openPinCode(
pinActivityResultLauncher, requireContext(),
PinMode.AUTH pinActivityResultLauncher,
) PinMode.AUTH
} else { )
doOpenPinCodePreferenceScreen() } else {
doOpenPinCodePreferenceScreen()
}
} }
} }
} }

View File

@ -24,9 +24,8 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ScrollView import android.widget.ScrollView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.withResumed
import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.args import com.airbnb.mvrx.args
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
@ -178,7 +177,7 @@ class UserListFragment :
// Scroll to the bottom when adding chips. When removing chips, do not scroll // Scroll to the bottom when adding chips. When removing chips, do not scroll
if (newNumberOfChips >= currentNumberOfChips) { if (newNumberOfChips >= currentNumberOfChips) {
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { withResumed {
views.chipGroupScrollView.fullScroll(ScrollView.FOCUS_DOWN) views.chipGroupScrollView.fullScroll(ScrollView.FOCUS_DOWN)
} }
} }