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

View file

@ -30,9 +30,8 @@ import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.withResumed
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -402,7 +401,9 @@ class HomeActivity :
private fun handleStartRecoverySetup() {
// To avoid IllegalStateException in case the transaction was executed after onSaveInstanceState
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.updatePadding
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.withResumed
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -1112,29 +1111,31 @@ class TimelineFragment :
private fun updateJumpToReadMarkerViewVisibility() {
if (isThreadTimeLine()) return
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
val state = timelineViewModel.awaitState()
val showJumpToUnreadBanner = when (state.unreadState) {
UnreadState.Unknown,
UnreadState.HasNoUnread -> false
is UnreadState.ReadMarkerNotLoaded -> true
is UnreadState.HasUnread -> {
if (state.canShowJumpToReadMarker) {
val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition()
val positionOfReadMarker = withContext(Dispatchers.Default) {
timelineEventController.getPositionOfReadMarker()
}
if (positionOfReadMarker == null) {
false
withResumed {
viewLifecycleOwner.lifecycleScope.launch {
val state = timelineViewModel.awaitState()
val showJumpToUnreadBanner = when (state.unreadState) {
UnreadState.Unknown,
UnreadState.HasNoUnread -> false
is UnreadState.ReadMarkerNotLoaded -> true
is UnreadState.HasUnread -> {
if (state.canShowJumpToReadMarker) {
val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition()
val positionOfReadMarker = withContext(Dispatchers.Default) {
timelineEventController.getPositionOfReadMarker()
}
if (positionOfReadMarker == null) {
false
} else {
positionOfReadMarker > lastVisibleItem
}
} 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) {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
permalinkHandler
.launch(requireActivity(), url, object : NavigationInterceptor {
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean {
requireActivity().finish()
return false
}
})
withResumed {
viewLifecycleOwner.lifecycleScope.launch {
permalinkHandler
.launch(requireActivity(), url, object : NavigationInterceptor {
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean {
requireActivity().finish()
return false
}
})
}
}
}
}

View file

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

View file

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

View file

@ -16,9 +16,7 @@
package im.vector.app.features.settings
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.Preference
import androidx.preference.SwitchPreference
import dagger.hilt.android.AndroidEntryPoint
@ -80,13 +78,13 @@ class VectorSettingsPinFragment :
override fun onResume() {
super.onResume()
updateBiometricPrefState(isPinCodeChecked = usePinCodePref.isChecked)
viewLifecycleOwner.lifecycleScope.launch {
refreshPinCodeStatus()
}
}
override fun bindPref() {
refreshPinCodeStatus()
usePinCodePref.setOnPreferenceChangeListener { _, value ->
val isChecked = (value as? Boolean).orFalse()
updateBiometricPrefState(isPinCodeChecked = isChecked)
@ -130,38 +128,34 @@ class VectorSettingsPinFragment :
.onFailure { Timber.e(it) }
}
private fun refreshPinCodeStatus() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
val hasPinCode = pinCodeStore.hasEncodedPin()
usePinCodePref.isChecked = hasPinCode
usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
if (hasPinCode) {
lifecycleScope.launch {
pinCodeStore.deletePinCode()
refreshPinCodeStatus()
}
} else {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.CREATE
)
}
true
}
changePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
if (hasPinCode) {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.MODIFY
)
}
true
private suspend fun refreshPinCodeStatus() {
val hasPinCode = pinCodeStore.hasEncodedPin()
usePinCodePref.isChecked = hasPinCode
usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
if (hasPinCode) {
lifecycleScope.launch {
pinCodeStore.deletePinCode()
refreshPinCodeStatus()
}
} 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 {
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 androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.withResumed
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreference
@ -190,6 +189,10 @@ class VectorSettingsSecurityPrivacyFragment :
rawService
.getElementWellknown(session.sessionParams)
?.isE2EByDefault() == false
refreshXSigningStatus()
// My device name may have been updated
refreshMyDevice()
}
}
@ -288,19 +291,6 @@ class VectorSettingsSecurityPrivacyFragment :
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 {
ThemeUtils.tintDrawable(
it,
@ -429,16 +419,18 @@ class VectorSettingsSecurityPrivacyFragment :
private fun openPinCodePreferenceScreen() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
val hasPinCode = pinCodeStore.hasEncodedPin()
if (hasPinCode) {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.AUTH
)
} else {
doOpenPinCodePreferenceScreen()
withResumed {
viewLifecycleOwner.lifecycleScope.launch {
val hasPinCode = pinCodeStore.hasEncodedPin()
if (hasPinCode) {
navigator.openPinCode(
requireContext(),
pinActivityResultLauncher,
PinMode.AUTH
)
} else {
doOpenPinCodePreferenceScreen()
}
}
}
}

View file

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