From d125cb5c017e0ddcd6fdd579f7599d0a2ce62a48 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Fri, 29 May 2020 11:36:27 +0200
Subject: [PATCH 1/3] Some cleanup: - use invalidate() from MvRx - use
 throttleFirst instead of debounce - remove useless observe on main thread -
 remove useless calls to super.invalidate()

---
 .../riotx/core/platform/VectorBaseActivity.kt |  1 -
 .../quads/SharedSecureStorageActivity.kt      | 13 ++----------
 .../quads/SharedSecuredStorageKeyFragment.kt  | 13 ++----------
 .../SharedSecuredStoragePassphraseFragment.kt |  4 +---
 .../BootstrapAccountPasswordFragment.kt       |  6 +-----
 .../BootstrapConfirmPassphraseFragment.kt     | 20 +++++++++----------
 .../BootstrapEnterPassphraseFragment.kt       |  6 ++----
 .../recover/BootstrapMigrateBackupFragment.kt |  6 ++----
 .../features/grouplist/GroupListFragment.kt   |  4 ++--
 .../room/breadcrumbs/BreadcrumbsFragment.kt   |  6 ++----
 .../home/room/detail/RoomDetailFragment.kt    |  3 +--
 .../home/room/list/RoomListFragment.kt        |  4 ++--
 .../riotx/features/login/LoginActivity.kt     |  9 +--------
 .../devices/DeviceListFragment.kt             |  1 -
 .../devices/DeviceTrustInfoActionFragment.kt  |  1 -
 .../signout/soft/SoftLogoutActivity.kt        | 16 ++++-----------
 16 files changed, 32 insertions(+), 81 deletions(-)

diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt
index 770a63a3fa..270e67cf34 100644
--- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt
@@ -95,7 +95,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
     protected val viewModelProvider
         get() = ViewModelProvider(this, viewModelFactory)
 
-    // TODO Other Activity should use this also
     protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
         viewEvents
                 .observe()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecureStorageActivity.kt b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecureStorageActivity.kt
index db37107dd6..27ab860994 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecureStorageActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecureStorageActivity.kt
@@ -31,7 +31,6 @@ import im.vector.riotx.core.di.ScreenComponent
 import im.vector.riotx.core.error.ErrorFormatter
 import im.vector.riotx.core.extensions.commitTransaction
 import im.vector.riotx.core.platform.SimpleFragmentActivity
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.parcel.Parcelize
 import kotlinx.android.synthetic.main.activity.*
 import javax.inject.Inject
@@ -59,17 +58,9 @@ class SharedSecureStorageActivity : SimpleFragmentActivity() {
         super.onCreate(savedInstanceState)
         toolbar.visibility = View.GONE
 
-        viewModel.viewEvents
-                .observe()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
-                    observeViewEvents(it)
-                }
-                .disposeOnDestroy()
+        viewModel.observeViewEvents { observeViewEvents(it) }
 
-        viewModel.subscribe(this) {
-            renderState(it)
-        }
+        viewModel.subscribe(this) { renderState(it) }
     }
 
     override fun onBackPressed() {
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
index 848166381e..993b2aeb26 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
@@ -22,22 +22,17 @@ import android.os.Bundle
 import android.view.View
 import android.view.inputmethod.EditorInfo
 import com.airbnb.mvrx.activityViewModel
-import com.airbnb.mvrx.withState
 import com.jakewharton.rxbinding3.widget.editorActionEvents
 import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.matrix.android.api.extensions.tryThis
 import im.vector.riotx.R
 import im.vector.riotx.core.platform.VectorBaseFragment
-import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.startImportTextFromFileIntent
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_ssss_access_from_key.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
-class SharedSecuredStorageKeyFragment @Inject constructor(
-        private val colorProvider: ColorProvider
-) : VectorBaseFragment() {
+class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment() {
 
     override fun getLayoutResId() = R.layout.fragment_ssss_access_from_key
 
@@ -48,8 +43,7 @@ class SharedSecuredStorageKeyFragment @Inject constructor(
         ssss_restore_with_key_text.text = getString(R.string.enter_secret_storage_input_key)
 
         ssss_key_enter_edittext.editorActionEvents()
-                .debounce(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
+                .throttleFirst(300, TimeUnit.MILLISECONDS)
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
@@ -102,9 +96,6 @@ class SharedSecuredStorageKeyFragment @Inject constructor(
         super.onActivityResult(requestCode, resultCode, data)
     }
 
-    override fun invalidate() = withState(sharedViewModel) { _ ->
-    }
-
     companion object {
         private const val IMPORT_FILE_REQ = 0
     }
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
index f5eb450fe1..5ecbf5a3fc 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
@@ -29,7 +29,6 @@ import im.vector.riotx.core.extensions.showPassword
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_ssss_access_from_passphrase.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -58,8 +57,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
                 .colorizeMatchingText(key, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
 
         ssss_passphrase_enter_edittext.editorActionEvents()
-                .debounce(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
+                .throttleFirst(300, TimeUnit.MILLISECONDS)
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt
index fcedd2926e..a790f63a38 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt
@@ -30,7 +30,6 @@ import im.vector.riotx.core.extensions.showPassword
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_account_password.*
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.ssss_view_show_password
@@ -56,8 +55,7 @@ class BootstrapAccountPasswordFragment @Inject constructor(
         bootstrapAccountPasswordEditText.hint = getString(R.string.account_password)
 
         bootstrapAccountPasswordEditText.editorActionEvents()
-                .debounce(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
+                .throttleFirst(300, TimeUnit.MILLISECONDS)
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
@@ -98,8 +96,6 @@ class BootstrapAccountPasswordFragment @Inject constructor(
     }
 
     override fun invalidate() = withState(sharedViewModel) { state ->
-        super.invalidate()
-
         if (state.step is BootstrapStep.AccountPassword) {
             val isPasswordVisible = state.step.isPasswordVisible
             bootstrapAccountPasswordEditText.showPassword(isPasswordVisible, updateCursor = false)
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
index df4d741bf1..779884f60b 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
@@ -31,7 +31,6 @@ import im.vector.riotx.core.extensions.showPassword
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -63,8 +62,7 @@ class BootstrapConfirmPassphraseFragment @Inject constructor(
         }
 
         ssss_passphrase_enter_edittext.editorActionEvents()
-                .debounce(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
+                .throttleFirst(300, TimeUnit.MILLISECONDS)
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
@@ -96,13 +94,15 @@ class BootstrapConfirmPassphraseFragment @Inject constructor(
             return@withState
         }
         val passphrase = ssss_passphrase_enter_edittext.text?.toString()
-        if (passphrase.isNullOrBlank()) {
-            ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message)
-        } else if (passphrase != state.passphrase) {
-            ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_does_not_match)
-        } else {
-            view?.hideKeyboard()
-            sharedViewModel.handle(BootstrapActions.DoInitialize(passphrase))
+        when {
+            passphrase.isNullOrBlank()     ->
+                ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message)
+            passphrase != state.passphrase ->
+                ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_does_not_match)
+            else                           -> {
+                view?.hideKeyboard()
+                sharedViewModel.handle(BootstrapActions.DoInitialize(passphrase))
+            }
         }
     }
 
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
index d1eee9ff3f..377ed2b1ea 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
@@ -30,7 +30,6 @@ import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
 import im.vector.riotx.features.settings.VectorLocale
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -53,12 +52,11 @@ class BootstrapEnterPassphraseFragment @Inject constructor(
 
         ssss_passphrase_enter_edittext.hint = getString(R.string.passphrase_enter_passphrase)
         withState(sharedViewModel) {
-            // set initial value (usefull when coming back)
+            // set initial value (useful when coming back)
             ssss_passphrase_enter_edittext.setText(it.passphrase ?: "")
         }
         ssss_passphrase_enter_edittext.editorActionEvents()
-                .debounce(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
+                .throttleFirst(300, TimeUnit.MILLISECONDS)
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt
index caf43721a0..1080c7322a 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt
@@ -39,7 +39,6 @@ import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
 import im.vector.riotx.core.utils.startImportTextFromFileIntent
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
 import kotlinx.android.synthetic.main.fragment_bootstrap_migrate_backup.*
 import java.util.concurrent.TimeUnit
@@ -57,12 +56,11 @@ class BootstrapMigrateBackupFragment @Inject constructor(
         super.onViewCreated(view, savedInstanceState)
 
         withState(sharedViewModel) {
-            // set initial value (usefull when coming back)
+            // set initial value (useful when coming back)
             bootstrapMigrateEditText.setText(it.passphrase ?: "")
         }
         bootstrapMigrateEditText.editorActionEvents()
-                .debounce(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
+                .throttleFirst(300, TimeUnit.MILLISECONDS)
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt
index e884761cdf..66c4a2325b 100644
--- a/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/grouplist/GroupListFragment.kt
@@ -22,6 +22,7 @@ import android.view.View
 import com.airbnb.mvrx.Incomplete
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
 import im.vector.matrix.android.api.session.group.model.GroupSummary
 import im.vector.riotx.R
 import im.vector.riotx.core.extensions.cleanup
@@ -50,7 +51,6 @@ class GroupListFragment @Inject constructor(
         groupController.callback = this
         stateView.contentView = groupListView
         groupListView.configureWith(groupController)
-        viewModel.subscribe { renderState(it) }
         viewModel.observeViewEvents {
             when (it) {
                 is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
@@ -64,7 +64,7 @@ class GroupListFragment @Inject constructor(
         super.onDestroyView()
     }
 
-    private fun renderState(state: GroupListViewState) {
+    override fun invalidate() = withState(viewModel) { state ->
         when (state.asyncGroups) {
             is Incomplete -> stateView.state = StateView.State.Loading
             is Success    -> stateView.state = StateView.State.Content
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
index 5407c73f35..6bae5b604f 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
@@ -19,6 +19,7 @@ package im.vector.riotx.features.home.room.breadcrumbs
 import android.os.Bundle
 import android.view.View
 import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
 import im.vector.riotx.R
 import im.vector.riotx.core.extensions.cleanup
 import im.vector.riotx.core.extensions.configureWith
@@ -42,8 +43,6 @@ class BreadcrumbsFragment @Inject constructor(
         super.onViewCreated(view, savedInstanceState)
         setupRecyclerView()
         sharedActionViewModel = activityViewModelProvider.get(RoomDetailSharedActionViewModel::class.java)
-
-        breadcrumbsViewModel.subscribe { renderState(it) }
     }
 
     override fun onDestroyView() {
@@ -57,8 +56,7 @@ class BreadcrumbsFragment @Inject constructor(
         breadcrumbsController.listener = this
     }
 
-    // TODO Use invalidate() ?
-    private fun renderState(state: BreadcrumbsViewState) {
+    override fun invalidate() = withState(breadcrumbsViewModel) { state ->
         breadcrumbsController.update(state)
     }
 
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index f042cdcefb..296f15fa92 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -262,7 +262,6 @@ class RoomDetailFragment @Inject constructor(
         roomToolbarContentView.debouncedClicks {
             navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
         }
-        roomDetailViewModel.subscribe { renderState(it) }
 
         sharedActionViewModel
                 .observe()
@@ -672,7 +671,7 @@ class RoomDetailFragment @Inject constructor(
         inviteView.callback = this
     }
 
-    private fun renderState(state: RoomDetailViewState) {
+    override fun invalidate() = withState(roomDetailViewModel) { state ->
         renderRoomSummary(state)
         val summary = state.asyncRoomSummary()
         val inviter = state.asyncInviter()
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt
index 1484e8009b..f4db464e6a 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt
@@ -32,6 +32,7 @@ import com.airbnb.mvrx.Incomplete
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
 import im.vector.matrix.android.api.failure.Failure
 import im.vector.matrix.android.api.session.room.model.Membership
 import im.vector.matrix.android.api.session.room.model.RoomSummary
@@ -99,7 +100,6 @@ class RoomListFragment @Inject constructor(
         setupCreateRoomButton()
         setupRecyclerView()
         sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
-        roomListViewModel.subscribe { renderState(it) }
         roomListViewModel.observeViewEvents {
             when (it) {
                 is RoomListViewEvents.Loading    -> showLoading(it.message)
@@ -243,7 +243,7 @@ class RoomListFragment @Inject constructor(
         }
     }
 
-    private fun renderState(state: RoomListViewState) {
+    override fun invalidate() = withState(roomListViewModel) { state ->
         when (state.asyncFilteredRooms) {
             is Incomplete -> renderLoading()
             is Success    -> renderSuccess(state)
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
index 99d8da490d..a8c9775980 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
@@ -45,7 +45,6 @@ import im.vector.riotx.features.home.HomeActivity
 import im.vector.riotx.features.login.terms.LoginTermsFragment
 import im.vector.riotx.features.login.terms.LoginTermsFragmentArgument
 import im.vector.riotx.features.login.terms.toLocalizedLoginTerms
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.activity_login.*
 import javax.inject.Inject
 
@@ -103,13 +102,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
                     updateWithState(it)
                 }
 
-        loginViewModel.viewEvents
-                .observe()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
-                    handleLoginViewEvents(it)
-                }
-                .disposeOnDestroy()
+        loginViewModel.observeViewEvents { handleLoginViewEvents(it) }
     }
 
     protected open fun addFirstFragment() {
diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt
index 93c51b2008..5fdb776b12 100644
--- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceListFragment.kt
@@ -58,7 +58,6 @@ class DeviceListFragment @Inject constructor(
 
     override fun invalidate() = withState(viewModel) {
         epoxyController.setData(it)
-        super.invalidate()
     }
 
     override fun onDeviceSelected(device: CryptoDeviceInfo) {
diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt
index d955e4c9dc..2e943b0eff 100644
--- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt
@@ -58,7 +58,6 @@ class DeviceTrustInfoActionFragment @Inject constructor(
 
     override fun invalidate() = withState(viewModel) {
         epoxyController.setData(it)
-        super.invalidate()
     }
 
     override fun onVerifyManually(device: CryptoDeviceInfo) {
diff --git a/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutActivity.kt b/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutActivity.kt
index 96dbbaf102..88ddc85ac1 100644
--- a/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutActivity.kt
@@ -32,7 +32,6 @@ import im.vector.riotx.core.extensions.replaceFragment
 import im.vector.riotx.features.MainActivity
 import im.vector.riotx.features.MainActivityArgs
 import im.vector.riotx.features.login.LoginActivity
-import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.activity_login.*
 import timber.log.Timber
 import javax.inject.Inject
@@ -57,18 +56,11 @@ class SoftLogoutActivity : LoginActivity() {
     override fun initUiAndData() {
         super.initUiAndData()
 
-        softLogoutViewModel
-                .subscribe(this) {
-                    updateWithState(it)
-                }
+        softLogoutViewModel.subscribe(this) {
+            updateWithState(it)
+        }
 
-        softLogoutViewModel.viewEvents
-                .observe()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
-                    handleSoftLogoutViewEvents(it)
-                }
-                .disposeOnDestroy()
+        softLogoutViewModel.observeViewEvents { handleSoftLogoutViewEvents(it) }
     }
 
     private fun handleSoftLogoutViewEvents(softLogoutViewEvents: SoftLogoutViewEvents) {

From 3fea2173f47bc9b220988cf427574c1b63766a25 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Fri, 29 May 2020 11:57:20 +0200
Subject: [PATCH 2/3] Move fun to a dedicated file.

---
 .../riotx/core/utils/JsonViewerStyler.kt      | 32 +++++++++++++++++++
 .../im/vector/riotx/core/utils/UserColor.kt   | 13 --------
 .../home/room/detail/RoomDetailFragment.kt    |  6 ++--
 .../settings/devtools/AccountDataFragment.kt  |  4 +--
 .../GossipingEventsPaperTrailFragment.kt      |  4 +--
 5 files changed, 39 insertions(+), 20 deletions(-)
 create mode 100644 vector/src/main/java/im/vector/riotx/core/utils/JsonViewerStyler.kt

diff --git a/vector/src/main/java/im/vector/riotx/core/utils/JsonViewerStyler.kt b/vector/src/main/java/im/vector/riotx/core/utils/JsonViewerStyler.kt
new file mode 100644
index 0000000000..94b08b22d6
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/core/utils/JsonViewerStyler.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.riotx.core.utils
+
+import im.vector.riotx.R
+import im.vector.riotx.core.resources.ColorProvider
+import org.billcarsonfr.jsonviewer.JSonViewerStyleProvider
+
+fun createJSonViewerStyleProvider(colorProvider: ColorProvider): JSonViewerStyleProvider {
+    return JSonViewerStyleProvider(
+            keyColor = colorProvider.getColor(R.color.riotx_accent),
+            secondaryColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary),
+            stringColor = colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color),
+            baseColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_primary),
+            booleanColor = colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color),
+            numberColor = colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color)
+    )
+}
diff --git a/vector/src/main/java/im/vector/riotx/core/utils/UserColor.kt b/vector/src/main/java/im/vector/riotx/core/utils/UserColor.kt
index 15c4ce8a15..1f8308cd5c 100644
--- a/vector/src/main/java/im/vector/riotx/core/utils/UserColor.kt
+++ b/vector/src/main/java/im/vector/riotx/core/utils/UserColor.kt
@@ -18,8 +18,6 @@ package im.vector.riotx.core.utils
 
 import androidx.annotation.ColorRes
 import im.vector.riotx.R
-import im.vector.riotx.core.resources.ColorProvider
-import org.billcarsonfr.jsonviewer.JSonViewerStyleProvider
 import kotlin.math.abs
 
 @ColorRes
@@ -39,14 +37,3 @@ fun getColorFromUserId(userId: String?): Int {
         else -> R.color.riotx_username_1
     }
 }
-
-fun jsonViewerStyler(colorProvider: ColorProvider): JSonViewerStyleProvider {
-    return JSonViewerStyleProvider(
-            keyColor = colorProvider.getColor(R.color.riotx_accent),
-            secondaryColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary),
-            stringColor = colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color),
-            baseColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_primary),
-            booleanColor = colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color),
-            numberColor = colorProvider.getColorFromAttribute(R.attr.vctr_notice_text_color)
-    )
-}
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index 296f15fa92..3f959746c0 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -110,10 +110,10 @@ import im.vector.riotx.core.utils.allGranted
 import im.vector.riotx.core.utils.checkPermissions
 import im.vector.riotx.core.utils.colorizeMatchingText
 import im.vector.riotx.core.utils.copyToClipboard
+import im.vector.riotx.core.utils.createJSonViewerStyleProvider
 import im.vector.riotx.core.utils.createUIHandler
 import im.vector.riotx.core.utils.getColorFromUserId
 import im.vector.riotx.core.utils.isValidUrl
-import im.vector.riotx.core.utils.jsonViewerStyler
 import im.vector.riotx.core.utils.openUrlInExternalBrowser
 import im.vector.riotx.core.utils.saveMedia
 import im.vector.riotx.core.utils.shareMedia
@@ -1207,14 +1207,14 @@ class RoomDetailFragment @Inject constructor(
                 JSonViewerDialog.newInstance(
                         action.content,
                         -1,
-                        jsonViewerStyler(colorProvider)
+                        createJSonViewerStyleProvider(colorProvider)
                 ).show(childFragmentManager, "JSON_VIEWER")
             }
             is EventSharedAction.ViewDecryptedSource        -> {
                 JSonViewerDialog.newInstance(
                         action.content,
                         -1,
-                        jsonViewerStyler(colorProvider)
+                        createJSonViewerStyleProvider(colorProvider)
                 ).show(childFragmentManager, "JSON_VIEWER")
             }
             is EventSharedAction.QuickReact                 -> {
diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devtools/AccountDataFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/devtools/AccountDataFragment.kt
index 7a57a03deb..ad8831124a 100644
--- a/vector/src/main/java/im/vector/riotx/features/settings/devtools/AccountDataFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/settings/devtools/AccountDataFragment.kt
@@ -29,7 +29,7 @@ import im.vector.riotx.core.extensions.configureWith
 import im.vector.riotx.core.platform.VectorBaseActivity
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
-import im.vector.riotx.core.utils.jsonViewerStyler
+import im.vector.riotx.core.utils.createJSonViewerStyleProvider
 import kotlinx.android.synthetic.main.fragment_generic_recycler.*
 import org.billcarsonfr.jsonviewer.JSonViewerDialog
 import javax.inject.Inject
@@ -73,7 +73,7 @@ class AccountDataFragment @Inject constructor(
         JSonViewerDialog.newInstance(
                 jsonString,
                 -1, // open All
-                jsonViewerStyler(colorProvider)
+                createJSonViewerStyleProvider(colorProvider)
         ).show(childFragmentManager, "JSON_VIEWER")
     }
 }
diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devtools/GossipingEventsPaperTrailFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/devtools/GossipingEventsPaperTrailFragment.kt
index d7ffd8adfa..9489fb8506 100644
--- a/vector/src/main/java/im/vector/riotx/features/settings/devtools/GossipingEventsPaperTrailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/settings/devtools/GossipingEventsPaperTrailFragment.kt
@@ -26,7 +26,7 @@ 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.resources.ColorProvider
-import im.vector.riotx.core.utils.jsonViewerStyler
+import im.vector.riotx.core.utils.createJSonViewerStyleProvider
 import kotlinx.android.synthetic.main.fragment_generic_recycler.*
 import org.billcarsonfr.jsonviewer.JSonViewerDialog
 import javax.inject.Inject
@@ -66,7 +66,7 @@ class GossipingEventsPaperTrailFragment @Inject constructor(
             JSonViewerDialog.newInstance(
                     it,
                     -1,
-                    jsonViewerStyler(colorProvider)
+                    createJSonViewerStyleProvider(colorProvider)
             ).show(childFragmentManager, "JSON_VIEWER")
         }
     }

From e2e1925796e3290b6b39c107718c93c27df6762a Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Tue, 2 Jun 2020 14:23:40 +0200
Subject: [PATCH 3/3] Restore `.observeOn(AndroidSchedulers.mainThread())`

---
 .../features/crypto/quads/SharedSecuredStorageKeyFragment.kt    | 2 ++
 .../crypto/quads/SharedSecuredStoragePassphraseFragment.kt      | 2 ++
 .../features/crypto/recover/BootstrapAccountPasswordFragment.kt | 2 ++
 .../crypto/recover/BootstrapConfirmPassphraseFragment.kt        | 2 ++
 .../features/crypto/recover/BootstrapEnterPassphraseFragment.kt | 2 ++
 .../features/crypto/recover/BootstrapMigrateBackupFragment.kt   | 2 ++
 6 files changed, 12 insertions(+)

diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
index 993b2aeb26..054c7a354a 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
@@ -28,6 +28,7 @@ import im.vector.matrix.android.api.extensions.tryThis
 import im.vector.riotx.R
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.utils.startImportTextFromFileIntent
+import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_ssss_access_from_key.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -44,6 +45,7 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
 
         ssss_key_enter_edittext.editorActionEvents()
                 .throttleFirst(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
index 5ecbf5a3fc..95d8579a9b 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
@@ -29,6 +29,7 @@ import im.vector.riotx.core.extensions.showPassword
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
+import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_ssss_access_from_passphrase.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -58,6 +59,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
 
         ssss_passphrase_enter_edittext.editorActionEvents()
                 .throttleFirst(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt
index a790f63a38..fd7d269e01 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapAccountPasswordFragment.kt
@@ -30,6 +30,7 @@ import im.vector.riotx.core.extensions.showPassword
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
+import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_account_password.*
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.ssss_view_show_password
@@ -56,6 +57,7 @@ class BootstrapAccountPasswordFragment @Inject constructor(
 
         bootstrapAccountPasswordEditText.editorActionEvents()
                 .throttleFirst(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
index 779884f60b..ebb6416317 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
@@ -31,6 +31,7 @@ import im.vector.riotx.core.extensions.showPassword
 import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
+import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -63,6 +64,7 @@ class BootstrapConfirmPassphraseFragment @Inject constructor(
 
         ssss_passphrase_enter_edittext.editorActionEvents()
                 .throttleFirst(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
index 377ed2b1ea..982f72c14e 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
@@ -30,6 +30,7 @@ import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
 import im.vector.riotx.features.settings.VectorLocale
+import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -57,6 +58,7 @@ class BootstrapEnterPassphraseFragment @Inject constructor(
         }
         ssss_passphrase_enter_edittext.editorActionEvents()
                 .throttleFirst(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt
index 1080c7322a..0b8e201edd 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapMigrateBackupFragment.kt
@@ -39,6 +39,7 @@ import im.vector.riotx.core.platform.VectorBaseFragment
 import im.vector.riotx.core.resources.ColorProvider
 import im.vector.riotx.core.utils.colorizeMatchingText
 import im.vector.riotx.core.utils.startImportTextFromFileIntent
+import io.reactivex.android.schedulers.AndroidSchedulers
 import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
 import kotlinx.android.synthetic.main.fragment_bootstrap_migrate_backup.*
 import java.util.concurrent.TimeUnit
@@ -61,6 +62,7 @@ class BootstrapMigrateBackupFragment @Inject constructor(
         }
         bootstrapMigrateEditText.editorActionEvents()
                 .throttleFirst(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
                 .subscribe {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()