Merge pull request #4645 from vector-im/feature/bma/cleanupOnclick

Cleanup onclick
This commit is contained in:
Benoit Marty 2021-12-07 13:22:54 +01:00 committed by GitHub
commit 74355aea43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 68 additions and 66 deletions

1
changelog.d/4645.misc Normal file
View file

@ -0,0 +1 @@
Debounce some clicks

View file

@ -62,7 +62,6 @@ import im.vector.app.core.extensions.restart
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.extensions.toMvRxBundle
import im.vector.app.core.flow.throttleFirst
import im.vector.app.core.utils.toast
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
@ -121,7 +120,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
protected fun View.debouncedClicks(onClicked: () -> Unit) {
clicks()
.throttleFirst(300)
.onEach { onClicked() }
.launchIn(lifecycleScope)
}

View file

@ -35,7 +35,6 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import dagger.hilt.android.EntryPointAccessors
import im.vector.app.core.di.ActivityEntryPoint
import im.vector.app.core.extensions.toMvRxBundle
import im.vector.app.core.flow.throttleFirst
import im.vector.app.core.utils.DimensionConverter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@ -168,7 +167,6 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
protected fun View.debouncedClicks(onClicked: () -> Unit) {
clicks()
.throttleFirst(300)
.onEach { onClicked() }
.launchIn(viewLifecycleOwner.lifecycleScope)
}

View file

@ -42,7 +42,6 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.extensions.toMvRxBundle
import im.vector.app.core.flow.throttleFirst
import im.vector.app.features.navigation.Navigator
import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
import kotlinx.coroutines.flow.launchIn
@ -239,7 +238,6 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
protected fun View.debouncedClicks(onClicked: () -> Unit) {
clicks()
.throttleFirst(300)
.onEach { onClicked() }
.launchIn(viewLifecycleOwner.lifecycleScope)
}

View file

@ -79,7 +79,7 @@ class AttachmentsPreviewFragment @Inject constructor(
applyInsets()
setupRecyclerViews()
setupToolbar(views.attachmentPreviewerToolbar)
views.attachmentPreviewerSendButton.setOnClickListener {
views.attachmentPreviewerSendButton.debouncedClicks {
setResultAndFinish()
}
}

View file

@ -35,7 +35,6 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
@ -62,8 +61,6 @@ import im.vector.app.features.home.room.detail.RoomDetailActivity
import im.vector.app.features.home.room.detail.RoomDetailArgs
import io.github.hyuwah.draggableviewlib.DraggableView
import io.github.hyuwah.draggableviewlib.setupDraggable
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.logger.LoggerTag
@ -142,12 +139,9 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
}
}
callViewModel.viewEvents
.stream()
.onEach {
callViewModel.observeViewEvents {
handleViewEvents(it)
}
.launchIn(lifecycleScope)
callViewModel.onEach(VectorCallViewState::callId, VectorCallViewState::isVideoCall) { _, isVideoCall ->
if (isVideoCall) {

View file

@ -77,7 +77,7 @@ class ContactsBookFragment @Inject constructor(
}
private fun setupConsentView() {
views.phoneBookSearchForMatrixContacts.setOnClickListener {
views.phoneBookSearchForMatrixContacts.debouncedClicks {
contactsBookViewModel.handle(ContactsBookAction.UserConsentRequest)
}
}

View file

@ -58,8 +58,8 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() :
views.keyInputLayout.error = newValue
}
views.keysRestoreButton.setOnClickListener { onRestoreFromKey() }
views.keysBackupImport.setOnClickListener { onImport() }
views.keysRestoreButton.debouncedClicks { onRestoreFromKey() }
views.keysBackupImport.debouncedClicks { onImport() }
views.keyTextEdit.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) }
}

View file

@ -58,8 +58,8 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
return@setOnEditorActionListener false
}
views.helperTextWithLink.setOnClickListener { onUseRecoveryKey() }
views.keysBackupRestoreWithPassphraseSubmit.setOnClickListener { onRestoreBackup() }
views.helperTextWithLink.debouncedClicks { onUseRecoveryKey() }
views.keysBackupRestoreWithPassphraseSubmit.debouncedClicks { onRestoreBackup() }
views.keysBackupPassphraseEnterEdittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) }
}

View file

@ -52,7 +52,7 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen
views.successText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date)
views.successDetailsText.isVisible = false
}
views.keysBackupSetupDoneButton.setOnClickListener { onDone() }
views.keysBackupSetupDoneButton.debouncedClicks { onDone() }
}
private fun onDone() {

View file

@ -45,8 +45,8 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment<Fr
views.keysBackupSetupStep1ManualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE
}
views.keysBackupSetupStep1Button.setOnClickListener { onButtonClick() }
views.keysBackupSetupStep1ManualExportButton.setOnClickListener { onManualExportClick() }
views.keysBackupSetupStep1Button.debouncedClicks { onButtonClick() }
views.keysBackupSetupStep1ManualExportButton.debouncedClicks { onManualExportClick() }
}
private fun onButtonClick() {

View file

@ -128,8 +128,8 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
}
private fun setupViews() {
views.keysBackupSetupStep2Button.setOnClickListener { doNext() }
views.keysBackupSetupStep2SkipButton.setOnClickListener { skipPassphrase() }
views.keysBackupSetupStep2Button.debouncedClicks { doNext() }
views.keysBackupSetupStep2SkipButton.debouncedClicks { skipPassphrase() }
views.keysBackupSetupStep2PassphraseEnterEdittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() }
views.keysBackupSetupStep2PassphraseConfirmEditText.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() }

View file

@ -85,9 +85,9 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
}
private fun setupViews() {
views.keysBackupSetupStep3FinishButton.setOnClickListener { onFinishButtonClicked() }
views.keysBackupSetupStep3CopyButton.setOnClickListener { onCopyButtonClicked() }
views.keysBackupSetupStep3RecoveryKeyText.setOnClickListener { onRecoveryKeyClicked() }
views.keysBackupSetupStep3FinishButton.debouncedClicks { onFinishButtonClicked() }
views.keysBackupSetupStep3CopyButton.debouncedClicks { onCopyButtonClicked() }
views.keysBackupSetupStep3RecoveryKeyText.debouncedClicks { onRecoveryKeyClicked() }
}
private fun onFinishButtonClicked() {
@ -127,7 +127,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
}
}
dialog.findViewById<View>(R.id.keys_backup_setup_save)?.setOnClickListener {
dialog.findViewById<View>(R.id.keys_backup_setup_save)?.debouncedClicks {
val userId = viewModel.userId
val timestamp = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
selectTxtFileToWrite(
@ -139,7 +139,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
dialog.dismiss()
}
dialog.findViewById<View>(R.id.keys_backup_setup_share)?.setOnClickListener {
dialog.findViewById<View>(R.id.keys_backup_setup_share)?.debouncedClicks {
startSharePlainTextIntent(
fragment = this,
activityResultLauncher = null,

View file

@ -898,7 +898,7 @@ class RoomDetailFragment @Inject constructor(
}
private fun setupJumpToReadMarkerView() {
views.jumpToReadMarkerView.setOnClickListener {
views.jumpToReadMarkerView.debouncedClicks {
onJumpToReadMarkerClicked()
}
views.jumpToReadMarkerView.setOnCloseIconClickListener {
@ -954,7 +954,7 @@ class RoomDetailFragment @Inject constructor(
super.onCreateOptionsMenu(menu, inflater)
// We use a custom layout for this menu item, so we need to set a ClickListener
menu.findItem(R.id.open_matrix_apps)?.let { menuItem ->
menuItem.actionView.setOnClickListener {
menuItem.actionView.debouncedClicks {
onOptionsItemSelected(menuItem)
}
}
@ -1463,7 +1463,7 @@ class RoomDetailFragment @Inject constructor(
callback = this@RoomDetailFragment
isVisible = true
render(inviter, VectorInviteView.Mode.LARGE, mainState.changeMembershipState)
setOnClickListener { }
setOnClickListener(null)
}
Unit
} else if (mainState.asyncInviter.complete) {

View file

@ -81,7 +81,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
}
private fun setupForgottenPasswordButton() {
views.forgetPasswordButton.setOnClickListener { forgetPasswordClicked() }
views.forgetPasswordButton.debouncedClicks { forgetPasswordClicked() }
}
private fun setupAutoFill(state: LoginViewState) {
@ -226,7 +226,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
}
private fun setupSubmitButton() {
views.loginSubmit.setOnClickListener { submit() }
views.loginSubmit.debouncedClicks { submit() }
combine(
views.loginField.textChanges().map { it.trim().isNotEmpty() },
views.passwordField.textChanges().map { it.isNotEmpty() }

View file

@ -78,8 +78,8 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra
}
private fun setupViews() {
views.loginGenericTextInputFormOtherButton.setOnClickListener { onOtherButtonClicked() }
views.loginGenericTextInputFormSubmit.setOnClickListener { submit() }
views.loginGenericTextInputFormOtherButton.debouncedClicks { onOtherButtonClicked() }
views.loginGenericTextInputFormSubmit.debouncedClicks { submit() }
}
private fun setupAutoFill() {

View file

@ -61,7 +61,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
}
private fun setupSubmitButton() {
views.resetPasswordSubmit.setOnClickListener { submit() }
views.resetPasswordSubmit.debouncedClicks { submit() }
combine(
views.resetPasswordEmail.textChanges().map { it.isEmail() },
views.passwordField.textChanges().map { it.isNotEmpty() }

View file

@ -40,7 +40,7 @@ class LoginResetPasswordMailConfirmationFragment @Inject constructor() : Abstrac
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
views.resetPasswordMailConfirmationSubmit.setOnClickListener { submit() }
views.resetPasswordMailConfirmationSubmit.debouncedClicks { submit() }
}
private fun setupUi(state: LoginViewState) {

View file

@ -35,7 +35,7 @@ class LoginResetPasswordSuccessFragment @Inject constructor() : AbstractLoginFra
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
views.resetPasswordSuccessSubmit.setOnClickListener { submit() }
views.resetPasswordSuccessSubmit.debouncedClicks { submit() }
}
private fun submit() {

View file

@ -43,11 +43,11 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment
}
private fun initViews() {
views.loginServerChoiceEmsLearnMore.setOnClickListener { learnMore() }
views.loginServerChoiceMatrixOrg.setOnClickListener { selectMatrixOrg() }
views.loginServerChoiceEms.setOnClickListener { selectEMS() }
views.loginServerChoiceOther.setOnClickListener { selectOther() }
views.loginServerIKnowMyIdSubmit.setOnClickListener { loginWithMatrixId() }
views.loginServerChoiceEmsLearnMore.debouncedClicks { learnMore() }
views.loginServerChoiceMatrixOrg.debouncedClicks { selectMatrixOrg() }
views.loginServerChoiceEms.debouncedClicks { selectEMS() }
views.loginServerChoiceOther.debouncedClicks { selectOther() }
views.loginServerIKnowMyIdSubmit.debouncedClicks { loginWithMatrixId() }
}
private fun updateSelectedChoice(state: LoginViewState) {

View file

@ -57,9 +57,9 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment<F
}
private fun setupViews() {
views.loginServerUrlFormLearnMore.setOnClickListener { learnMore() }
views.loginServerUrlFormClearHistory.setOnClickListener { clearHistory() }
views.loginServerUrlFormSubmit.setOnClickListener { submit() }
views.loginServerUrlFormLearnMore.debouncedClicks { learnMore() }
views.loginServerUrlFormClearHistory.debouncedClicks { clearHistory() }
views.loginServerUrlFormSubmit.debouncedClicks { submit() }
}
private fun setupHomeServerField() {

View file

@ -43,8 +43,8 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLogi
}
private fun setupViews() {
views.loginSignupSigninSubmit.setOnClickListener { submit() }
views.loginSignupSigninSignIn.setOnClickListener { signIn() }
views.loginSignupSigninSubmit.debouncedClicks { submit() }
views.loginSignupSigninSignIn.debouncedClicks { signIn() }
}
private fun setupUi(state: LoginViewState) {

View file

@ -73,7 +73,7 @@ class LoginTermsFragment @Inject constructor(
}
private fun setupViews() {
views.loginTermsSubmit.setOnClickListener { submit() }
views.loginTermsSubmit.debouncedClicks { submit() }
}
override fun onDestroyView() {

View file

@ -85,11 +85,11 @@ class AccountCreatedFragment @Inject constructor(
}
private fun setupClickListener() {
views.loginAccountCreatedMessage.setOnClickListener {
views.loginAccountCreatedMessage.debouncedClicks {
// Update display name
displayDialog()
}
views.loginAccountCreatedAvatar.setOnClickListener {
views.loginAccountCreatedAvatar.debouncedClicks {
galleryOrCameraDialogHelper.show()
}
}
@ -120,8 +120,8 @@ class AccountCreatedFragment @Inject constructor(
}
private fun setupSubmitButton() {
views.loginAccountCreatedLater.setOnClickListener { terminate() }
views.loginAccountCreatedDone.setOnClickListener { terminate() }
views.loginAccountCreatedLater.debouncedClicks { terminate() }
views.loginAccountCreatedDone.debouncedClicks { terminate() }
}
private fun terminate() {

View file

@ -146,12 +146,12 @@ class RoomProfileFragment @Inject constructor(
headerViews.roomProfileNameView,
views.matrixProfileToolbarTitleView
).forEach {
it.setOnClickListener {
it.debouncedClicks {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomSettings)
}
}
// Shortcut to room alias
headerViews.roomProfileAliasView.setOnClickListener {
headerViews.roomProfileAliasView.debouncedClicks {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomAliasesSettings)
}
// Open Avatar
@ -159,7 +159,7 @@ class RoomProfileFragment @Inject constructor(
headerViews.roomProfileAvatarView,
views.matrixProfileToolbarAvatarImageView
).forEach { view ->
view.setOnClickListener { onAvatarClicked(view) }
view.debouncedClicks { onAvatarClicked(view) }
}
}

View file

@ -20,6 +20,7 @@ import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.annotation.CallSuper
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R
@ -27,7 +28,10 @@ import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.toast
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.Session
import reactivecircus.flowbinding.android.view.clicks
import timber.log.Timber
abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat() {
@ -42,6 +46,16 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat() {
protected lateinit var session: Session
protected lateinit var errorFormatter: ErrorFormatter
/* ==========================================================================================
* Views
* ========================================================================================== */
protected fun View.debouncedClicks(onClicked: () -> Unit) {
clicks()
.onEach { onClicked() }
.launchIn(viewLifecycleOwner.lifecycleScope)
}
abstract val preferenceXmlRes: Int
@CallSuper

View file

@ -418,7 +418,7 @@ class VectorSettingsGeneralFragment @Inject constructor(
}
}
updateButton.setOnClickListener {
updateButton.debouncedClicks {
// Hide passwords during processing
views.changePasswordOldPwdText.hidePassword()
views.changePasswordNewPwdText.hidePassword()

View file

@ -197,7 +197,7 @@ class VectorSettingsPreferencesFragment @Inject constructor(
.forEachIndexed { i, v ->
v.isChecked = i == index
v.setOnClickListener {
v.debouncedClicks {
dialog.dismiss()
FontScale.updateFontScale(activity, i)
vectorConfiguration.applyToApplicationContext()

View file

@ -446,7 +446,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
val importDialog = builder.show()
views.dialogE2eKeysImportButton.setOnClickListener {
views.dialogE2eKeysImportButton.debouncedClicks {
val password = views.dialogE2eKeysPassphraseEditText.text.toString()
displayLoadingView()

View file

@ -118,7 +118,7 @@ class IncomingShareFragment @Inject constructor(
return true
}
})
views.sendShareButton.setOnClickListener {
views.sendShareButton.debouncedClicks {
handleSendShare()
}
}

View file

@ -42,7 +42,7 @@ class SignedOutActivity : VectorBaseActivity<ActivitySignedOutBinding>() {
}
private fun setupViews() {
views.signedOutSubmit.setOnClickListener { submit() }
views.signedOutSubmit.debouncedClicks { submit() }
}
private fun submit() {

View file

@ -40,7 +40,6 @@ class WidgetActivity : VectorBaseActivity<ActivityWidgetBinding>(),
ToolbarConfigurable {
companion object {
private const val WIDGET_FRAGMENT_TAG = "WIDGET_FRAGMENT_TAG"
private const val WIDGET_PERMISSION_FRAGMENT_TAG = "WIDGET_PERMISSION_FRAGMENT_TAG"
private const val EXTRA_RESULT = "EXTRA_RESULT"
@ -56,7 +55,7 @@ class WidgetActivity : VectorBaseActivity<ActivityWidgetBinding>(),
return intent.extras?.getSerializable(EXTRA_RESULT) as? Content
}
fun createResultIntent(content: Content): Intent {
private fun createResultIntent(content: Content): Intent {
return Intent().apply {
putExtra(EXTRA_RESULT, content as Serializable)
}