From 876359539fd4fb09706bc39a49ab732cfe612a14 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 15 Dec 2020 18:46:10 +0100 Subject: [PATCH 001/224] Reduce dependency on Butterknife: remove usage of @OnClick and @OnTextChange --- .../app/features/debug/DebugMenuActivity.kt | 33 ++++++++++--------- .../app/core/platform/VectorBaseActivity.kt | 2 ++ .../app/core/ui/views/KeysBackupBanner.kt | 6 ++-- .../app/features/call/CallControlsView.kt | 30 ++++++++--------- .../KeysBackupRestoreFromKeyFragment.kt | 18 +++++----- ...KeysBackupRestoreFromPassphraseFragment.kt | 22 ++++++------- .../KeysBackupRestoreSuccessFragment.kt | 6 ++-- .../setup/KeysBackupSetupStep1Fragment.kt | 11 ++++--- .../setup/KeysBackupSetupStep2Fragment.kt | 29 +++++++++------- .../setup/KeysBackupSetupStep3Fragment.kt | 19 +++++++---- .../app/features/login/LoginFragment.kt | 13 +++++--- .../LoginGenericTextInputFormFragment.kt | 13 +++++--- .../login/LoginResetPasswordFragment.kt | 6 ++-- ...inResetPasswordMailConfirmationFragment.kt | 12 +++++-- .../LoginResetPasswordSuccessFragment.kt | 13 ++++++-- .../login/LoginServerSelectionFragment.kt | 25 +++++++------- .../login/LoginServerUrlFormFragment.kt | 19 ++++++----- .../LoginSignUpSignInSelectionFragment.kt | 27 ++++++++++----- .../app/features/login/LoginSplashFragment.kt | 17 ++++++++-- .../login/terms/LoginTermsFragment.kt | 10 ++++-- .../features/rageshake/BugReportActivity.kt | 13 +++++--- .../signout/hard/SignedOutActivity.kt | 16 +++++++-- .../RoomWidgetPermissionBottomSheet.kt | 20 ++++++++--- 23 files changed, 234 insertions(+), 146 deletions(-) diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 9cca462d1a..1d9de30a0f 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -24,7 +24,6 @@ import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.Person import androidx.core.content.getSystemService -import butterknife.OnClick import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ScreenComponent @@ -66,24 +65,32 @@ class DebugMenuActivity : VectorBaseActivity() { val string = buffer.toString(Charsets.ISO_8859_1) renderQrCode(string) + setupViews() + } + + private fun setupViews() { + debug_test_text_view_link.setOnClickListener { testTextViewLink() } + debug_show_sas_emoji.setOnClickListener { showSasEmoji() } + debug_test_notification.setOnClickListener { testNotification() } + debug_test_material_theme_light.setOnClickListener { testMaterialThemeLight() } + debug_test_material_theme_dark.setOnClickListener { testMaterialThemeDark() } + debug_test_crash.setOnClickListener { testCrash() } + debug_scan_qr_code.setOnClickListener { scanQRCode() } } private fun renderQrCode(text: String) { debug_qr_code.setData(text) } - @OnClick(R.id.debug_test_text_view_link) - fun testTextViewLink() { + private fun testTextViewLink() { startActivity(Intent(this, TestLinkifyActivity::class.java)) } - @OnClick(R.id.debug_show_sas_emoji) - fun showSasEmoji() { + private fun showSasEmoji() { startActivity(Intent(this, DebugSasEmojiActivity::class.java)) } - @OnClick(R.id.debug_test_notification) - fun testNotification() { + private fun testNotification() { val notificationManager = getSystemService()!! // Create channel first @@ -166,23 +173,19 @@ class DebugMenuActivity : VectorBaseActivity() { ) } - @OnClick(R.id.debug_test_material_theme_light) - fun testMaterialThemeLight() { + private fun testMaterialThemeLight() { startActivity(Intent(this, DebugMaterialThemeLightActivity::class.java)) } - @OnClick(R.id.debug_test_material_theme_dark) - fun testMaterialThemeDark() { + private fun testMaterialThemeDark() { startActivity(Intent(this, DebugMaterialThemeDarkActivity::class.java)) } - @OnClick(R.id.debug_test_crash) - fun testCrash() { + private fun testCrash() { throw RuntimeException("Application crashed from user demand") } - @OnClick(R.id.debug_scan_qr_code) - fun scanQRCode() { + private fun scanQRCode() { if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) { doScanQRCode() } diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index f58f0b87ae..f895b2014f 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -26,6 +26,7 @@ import android.view.MenuItem import android.view.View import android.view.WindowManager import androidx.annotation.AttrRes +import androidx.annotation.CallSuper import androidx.annotation.LayoutRes import androidx.annotation.MainThread import androidx.annotation.MenuRes @@ -176,6 +177,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { uiDisposables.add(this) } + @CallSuper override fun onCreate(savedInstanceState: Bundle?) { Timber.i("onCreate Activity ${javaClass.simpleName}") val vectorComponent = getVectorComponent() diff --git a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt index f4890780b5..244f12c24a 100755 --- a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt @@ -25,9 +25,9 @@ import androidx.core.content.edit import androidx.core.view.isVisible import butterknife.BindView import butterknife.ButterKnife -import butterknife.OnClick import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences +import kotlinx.android.synthetic.main.view_keys_backup_banner.view.* import timber.log.Timber /** @@ -100,8 +100,7 @@ class KeysBackupBanner @JvmOverloads constructor( } } - @OnClick(R.id.view_keys_backup_banner_close) - internal fun onCloseClicked() { + private fun onCloseClicked() { state.let { when (it) { is State.Setup -> { @@ -138,6 +137,7 @@ class KeysBackupBanner @JvmOverloads constructor( setOnClickListener(this) textView1.setOnClickListener(this) textView2.setOnClickListener(this) + view_keys_backup_banner_close.setOnClickListener { onCloseClicked() } } private fun renderInitial() { diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt index d749bcd351..4e46ace192 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt @@ -25,7 +25,6 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import butterknife.BindView import butterknife.ButterKnife -import butterknife.OnClick import im.vector.app.R import kotlinx.android.synthetic.main.view_call_controls.view.* import org.matrix.android.sdk.api.session.call.CallState @@ -59,40 +58,41 @@ class CallControlsView @JvmOverloads constructor( ConstraintLayout.inflate(context, R.layout.view_call_controls, this) // layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) ButterKnife.bind(this) + + iv_icr_accept_call.setOnClickListener { acceptIncomingCall() } + iv_icr_end_call.setOnClickListener { declineIncomingCall() } + iv_end_call.setOnClickListener { endOngoingCall() } + iv_mute_toggle.setOnClickListener { toggleMute() } + iv_video_toggle.setOnClickListener { toggleVideo() } + iv_leftMiniControl.setOnClickListener { returnToChat() } + iv_more.setOnClickListener { moreControlOption() } } - @OnClick(R.id.iv_icr_accept_call) - fun acceptIncomingCall() { + private fun acceptIncomingCall() { interactionListener?.didAcceptIncomingCall() } - @OnClick(R.id.iv_icr_end_call) - fun declineIncomingCall() { + private fun declineIncomingCall() { interactionListener?.didDeclineIncomingCall() } - @OnClick(R.id.iv_end_call) - fun endOngoingCall() { + private fun endOngoingCall() { interactionListener?.didEndCall() } - @OnClick(R.id.iv_mute_toggle) - fun toggleMute() { + private fun toggleMute() { interactionListener?.didTapToggleMute() } - @OnClick(R.id.iv_video_toggle) - fun toggleVideo() { + private fun toggleVideo() { interactionListener?.didTapToggleVideo() } - @OnClick(R.id.iv_leftMiniControl) - fun returnToChat() { + private fun returnToChat() { interactionListener?.returnToChat() } - @OnClick(R.id.iv_more) - fun moreControlOption() { + private fun moreControlOption() { interactionListener?.didTapMore() } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt index 580a3443e7..1db7797560 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt @@ -17,19 +17,18 @@ package im.vector.app.features.crypto.keysbackup.restore import android.app.Activity import android.os.Bundle -import android.text.Editable import android.view.View import android.view.inputmethod.EditorInfo import android.widget.EditText +import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer import butterknife.BindView -import butterknife.OnClick -import butterknife.OnTextChanged import com.google.android.material.textfield.TextInputLayout import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.startImportTextFromFileIntent +import kotlinx.android.synthetic.main.fragment_keys_backup_restore_from_key.* import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject @@ -64,17 +63,19 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue -> mKeyInputLayout.error = newValue }) + + keys_restore_button.setOnClickListener { onRestoreFromKey() } + keys_backup_import.setOnClickListener { onImport() } + keys_restore_key_enter_edittext.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) } } - @OnTextChanged(R.id.keys_restore_key_enter_edittext) - fun onRestoreKeyTextEditChange(s: Editable?) { + private fun onRestoreKeyTextEditChange(s: CharSequence?) { s?.toString()?.let { viewModel.updateCode(it) } } - @OnClick(R.id.keys_restore_button) - fun onRestoreFromKey() { + private fun onRestoreFromKey() { val value = viewModel.recoveryCode.value if (value.isNullOrBlank()) { viewModel.recoveryCodeErrorText.value = context?.getString(R.string.keys_backup_recovery_code_empty_error_message) @@ -83,8 +84,7 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() } } - @OnClick(R.id.keys_backup_import) - fun onImport() { + private fun onImport() { startImportTextFromFileIntent(requireContext(), textFileStartForActivityResult) } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt index 79aa728da1..bffed5c1bb 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt @@ -16,7 +16,6 @@ package im.vector.app.features.crypto.keysbackup.restore import android.os.Bundle -import android.text.Editable import android.text.SpannableString import android.text.style.ClickableSpan import android.view.View @@ -25,14 +24,14 @@ import android.widget.EditText import android.widget.ImageView import android.widget.TextView import androidx.core.text.set +import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer import butterknife.BindView -import butterknife.OnClick -import butterknife.OnTextChanged import com.google.android.material.textfield.TextInputLayout import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment +import kotlinx.android.synthetic.main.fragment_keys_backup_restore_from_passphrase.* import javax.inject.Inject class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment() { @@ -54,8 +53,7 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase @BindView(R.id.keys_backup_passphrase_help_with_link) lateinit var helperTextWithLink: TextView - @OnClick(R.id.keys_backup_view_show_password) - fun toggleVisibilityMode() { + private fun toggleVisibilityMode() { viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false) } @@ -84,6 +82,11 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase } return@setOnEditorActionListener false } + + keys_backup_view_show_password.setOnClickListener { toggleVisibilityMode() } + keys_backup_passphrase_help_with_link.setOnClickListener { onUseRecoveryKey() } + keys_backup_restore_with_passphrase_submit.setOnClickListener { onRestoreBackup() } + keys_backup_passphrase_enter_edittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) } } private fun spannableStringForHelperText(): SpannableString { @@ -102,18 +105,15 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase return spanString } - @OnTextChanged(R.id.keys_backup_passphrase_enter_edittext) - fun onPassphraseTextEditChange(s: Editable?) { + private fun onPassphraseTextEditChange(s: CharSequence?) { s?.toString()?.let { viewModel.updatePassphrase(it) } } - @OnClick(R.id.keys_backup_passphrase_help_with_link) - fun onUseRecoveryKey() { + private fun onUseRecoveryKey() { sharedViewModel.moveToRecoverWithKey() } - @OnClick(R.id.keys_backup_restore_with_passphrase_submit) - fun onRestoreBackup() { + private fun onRestoreBackup() { val value = viewModel.passphrase.value if (value.isNullOrBlank()) { viewModel.passphraseErrorText.value = getString(R.string.passphrase_empty_error_message) diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt index b4969d28b7..710bd97bbd 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt @@ -20,10 +20,10 @@ import android.view.View import android.widget.TextView import androidx.core.view.isVisible import butterknife.BindView -import butterknife.OnClick import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.LiveEvent +import kotlinx.android.synthetic.main.fragment_keys_backup_restore_success.* import javax.inject.Inject class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment() { @@ -56,10 +56,10 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date) mSuccessDetailsText.isVisible = false } + keys_backup_setup_done_button.setOnClickListener { onDone() } } - @OnClick(R.id.keys_backup_setup_done_button) - fun onDone() { + private fun onDone() { sharedViewModel.importRoomKeysFinishWithResult.value = LiveEvent(sharedViewModel.importKeyResult!!) } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt index f855b86b6c..12017a3562 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt @@ -22,10 +22,10 @@ import android.widget.Button import android.widget.TextView import androidx.lifecycle.Observer import butterknife.BindView -import butterknife.OnClick import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.LiveEvent +import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step1.* import javax.inject.Inject class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() { @@ -51,15 +51,16 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() advancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE manualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE }) + + keys_backup_setup_step1_button.setOnClickListener { onButtonClick() } + keys_backup_setup_step1_manualExport.setOnClickListener { onManualExportClick() } } - @OnClick(R.id.keys_backup_setup_step1_button) - fun onButtonClick() { + private fun onButtonClick() { viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2) } - @OnClick(R.id.keys_backup_setup_step1_manualExport) - fun onManualExportClick() { + private fun onManualExportClick() { viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_MANUAL_EXPORT) } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt index af279c9140..4f3a73e14b 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt @@ -21,12 +21,11 @@ import android.view.ViewGroup import android.view.inputmethod.EditorInfo import android.widget.EditText import android.widget.ImageView +import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer import androidx.lifecycle.viewModelScope import androidx.transition.TransitionManager import butterknife.BindView -import butterknife.OnClick -import butterknife.OnTextChanged import com.google.android.material.textfield.TextInputLayout import com.nulabinc.zxcvbn.Zxcvbn import im.vector.app.R @@ -34,6 +33,7 @@ import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.ui.views.PasswordStrengthBar import im.vector.app.features.settings.VectorLocale +import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step2.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import javax.inject.Inject @@ -65,14 +65,12 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() private val zxcvbn = Zxcvbn() - @OnTextChanged(R.id.keys_backup_passphrase_enter_edittext) - fun onPassphraseChanged() { + private fun onPassphraseChanged() { viewModel.passphrase.value = mPassphraseTextEdit.text.toString() viewModel.confirmPassphraseError.value = null } - @OnTextChanged(R.id.keys_backup_passphrase_confirm_edittext) - fun onConfirmPassphraseChanged() { + private fun onConfirmPassphraseChanged() { viewModel.confirmPassphrase.value = mPassphraseConfirmTextEdit.text.toString() } @@ -85,6 +83,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() viewModel.shouldPromptOnBack = true bindViewToViewModel() + setupViews() } /* ========================================================================================== @@ -159,13 +158,20 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() } } - @OnClick(R.id.keys_backup_view_show_password) - fun toggleVisibilityMode() { + private fun setupViews() { + keys_backup_view_show_password.setOnClickListener { toggleVisibilityMode() } + keys_backup_setup_step2_button.setOnClickListener { doNext() } + keys_backup_setup_step2_skip_button.setOnClickListener { skipPassphrase() } + + keys_backup_passphrase_enter_edittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged()} + keys_backup_passphrase_confirm_edittext.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged()} + } + + private fun toggleVisibilityMode() { viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false) } - @OnClick(R.id.keys_backup_setup_step2_button) - fun doNext() { + private fun doNext() { when { viewModel.passphrase.value.isNullOrEmpty() -> { viewModel.passphraseError.value = context?.getString(R.string.passphrase_empty_error_message) @@ -184,8 +190,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() } } - @OnClick(R.id.keys_backup_setup_step2_skip_button) - fun skipPassphrase() { + private fun skipPassphrase() { when { viewModel.passphrase.value.isNullOrEmpty() -> { // Generate a recovery key for the user diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index 78471c6848..c686b23b53 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -27,7 +27,6 @@ import androidx.core.view.isVisible import androidx.lifecycle.Observer import arrow.core.Try import butterknife.BindView -import butterknife.OnClick import com.google.android.material.bottomsheet.BottomSheetDialog import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult @@ -36,6 +35,7 @@ import im.vector.app.core.utils.LiveEvent import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.selectTxtFileToWrite import im.vector.app.core.utils.startSharePlainTextIntent +import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step3.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -88,10 +88,17 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() mRecoveryKeyTextView.isVisible = false } }) + + setupViews() } - @OnClick(R.id.keys_backup_setup_step3_button) - fun onFinishButtonClicked() { + private fun setupViews() { + keys_backup_setup_step3_button.setOnClickListener { onFinishButtonClicked() } + keys_backup_setup_step3_copy_button.setOnClickListener { onCopyButtonClicked() } + keys_backup_recovery_key_text.setOnClickListener { onRecoveryKeyClicked() } + } + + private fun onFinishButtonClicked() { if (viewModel.megolmBackupCreationInfo == null) { // nothing } else { @@ -103,8 +110,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() } } - @OnClick(R.id.keys_backup_setup_step3_copy_button) - fun onCopyButtonClicked() { + private fun onCopyButtonClicked() { val dialog = BottomSheetDialog(requireActivity()) dialog.setContentView(R.layout.bottom_sheet_save_recovery_key) dialog.setCanceledOnTouchOutside(true) @@ -155,8 +161,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() dialog.show() } - @OnClick(R.id.keys_backup_recovery_key_text) - fun onRecoveryKeyClicked() { + private fun onRecoveryKeyClicked() { viewModel.recoveryKey.value?.let { viewModel.copyHasBeenMade = true diff --git a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt index 7d98f1f8ee..9cb3428c80 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt @@ -23,7 +23,6 @@ import android.view.inputmethod.EditorInfo import androidx.autofill.HintConstants import androidx.core.text.isDigitsOnly import androidx.core.view.isVisible -import butterknife.OnClick import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success @@ -66,6 +65,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { super.onViewCreated(view, savedInstanceState) setupSubmitButton() + setupForgottenPasswordButton() setupPasswordReveal() passwordField.setOnEditorActionListener { _, actionId, _ -> @@ -77,6 +77,10 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { } } + private fun setupForgottenPasswordButton() { + forgetPasswordButton.setOnClickListener { forgetPasswordClicked() } + } + private fun setupAutoFill(state: LoginViewState) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { when (state.signMode) { @@ -96,8 +100,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { } } - @OnClick(R.id.loginSubmit) - fun submit() { + private fun submit() { cleanupUi() val login = loginField.text.toString() @@ -200,6 +203,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { } private fun setupSubmitButton() { + loginSubmit.setOnClickListener { submit() } Observable .combineLatest( loginField.textChanges().map { it.trim().isNotEmpty() }, @@ -216,8 +220,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { .disposeOnDestroyView() } - @OnClick(R.id.forgetPasswordButton) - fun forgetPasswordClicked() { + private fun forgetPasswordClicked() { loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnForgetPasswordClicked)) } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt index 453575b91b..70ef97c209 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt @@ -23,7 +23,6 @@ import android.text.InputType import android.view.View import androidx.autofill.HintConstants import androidx.core.view.isVisible -import butterknife.OnClick import com.airbnb.mvrx.args import com.google.i18n.phonenumbers.NumberParseException import com.google.i18n.phonenumbers.PhoneNumberUtil @@ -64,12 +63,18 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + setupViews() setupUi() setupSubmitButton() setupTil() setupAutoFill() } + private fun setupViews() { + loginGenericTextInputFormOtherButton.setOnClickListener { onOtherButtonClicked() } + loginGenericTextInputFormSubmit.setOnClickListener { submit() } + } + private fun setupAutoFill() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { loginGenericTextInputFormTextInput.setAutofillHints( @@ -126,8 +131,7 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra } } - @OnClick(R.id.loginGenericTextInputFormOtherButton) - fun onOtherButtonClicked() { + private fun onOtherButtonClicked() { when (params.mode) { TextInputFormFragmentMode.ConfirmMsisdn -> { loginViewModel.handle(LoginAction.SendAgainThreePid) @@ -138,8 +142,7 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra } } - @OnClick(R.id.loginGenericTextInputFormSubmit) - fun submit() { + private fun submit() { cleanupUi() val text = loginGenericTextInputFormTextInput.text.toString() diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt index 9ca266c417..5b6fc362cd 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt @@ -19,7 +19,6 @@ package im.vector.app.features.login import android.os.Bundle import android.view.View import androidx.appcompat.app.AlertDialog -import butterknife.OnClick import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success @@ -59,6 +58,8 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment() } private fun setupSubmitButton() { + resetPasswordSubmit.setOnClickListener { submit() } + Observable .combineLatest( resetPasswordEmail.textChanges().map { it.isEmail() }, @@ -75,8 +76,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment() .disposeOnDestroyView() } - @OnClick(R.id.resetPasswordSubmit) - fun submit() { + private fun submit() { cleanupUi() if (showWarning) { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt index 577edf754b..08678c020c 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt @@ -16,8 +16,9 @@ package im.vector.app.features.login +import android.os.Bundle +import android.view.View import androidx.appcompat.app.AlertDialog -import butterknife.OnClick import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Success import im.vector.app.R @@ -32,12 +33,17 @@ class LoginResetPasswordMailConfirmationFragment @Inject constructor() : Abstrac override fun getLayoutResId() = R.layout.fragment_login_reset_password_mail_confirmation + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetPasswordMailConfirmationSubmit.setOnClickListener { submit() } + } + private fun setupUi(state: LoginViewState) { resetPasswordMailConfirmationNotice.text = getString(R.string.login_reset_password_mail_confirmation_notice, state.resetPasswordEmail) } - @OnClick(R.id.resetPasswordMailConfirmationSubmit) - fun submit() { + private fun submit() { loginViewModel.handle(LoginAction.ResetPasswordMailConfirmed) } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt index 93c987f2db..1a428f57df 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt @@ -16,8 +16,10 @@ package im.vector.app.features.login -import butterknife.OnClick +import android.os.Bundle +import android.view.View import im.vector.app.R +import kotlinx.android.synthetic.main.fragment_login_reset_password_success.* import javax.inject.Inject /** @@ -27,8 +29,13 @@ class LoginResetPasswordSuccessFragment @Inject constructor() : AbstractLoginFra override fun getLayoutResId() = R.layout.fragment_login_reset_password_success - @OnClick(R.id.resetPasswordSuccessSubmit) - fun submit() { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetPasswordSuccessSubmit.setOnClickListener { submit() } + } + + private fun submit() { loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnResetPasswordMailConfirmationSuccessDone)) } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt index c9460e1a41..c365844c6e 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt @@ -18,7 +18,6 @@ package im.vector.app.features.login import android.os.Bundle import android.view.View -import butterknife.OnClick import im.vector.app.R import im.vector.app.core.utils.openUrlInChromeCustomTab import kotlinx.android.synthetic.main.fragment_login_server_selection.* @@ -35,9 +34,18 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + initViews() initTextViews() } + private fun initViews() { + loginServerChoiceEmsLearnMore.setOnClickListener { learnMore() } + loginServerChoiceMatrixOrg.setOnClickListener { selectMatrixOrg() } + loginServerChoiceEms.setOnClickListener { selectEMS() } + loginServerChoiceOther.setOnClickListener { selectOther() } + loginServerIKnowMyIdSubmit.setOnClickListener { loginWithMatrixId() } + } + private fun updateSelectedChoice(state: LoginViewState) { loginServerChoiceMatrixOrg.isChecked = state.serverType == ServerType.MatrixOrg } @@ -49,28 +57,23 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment } } - @OnClick(R.id.loginServerChoiceEmsLearnMore) - fun learnMore() { + private fun learnMore() { openUrlInChromeCustomTab(requireActivity(), null, EMS_LINK) } - @OnClick(R.id.loginServerChoiceMatrixOrg) - fun selectMatrixOrg() { + private fun selectMatrixOrg() { loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg)) } - @OnClick(R.id.loginServerChoiceEms) - fun selectEMS() { + private fun selectEMS() { loginViewModel.handle(LoginAction.UpdateServerType(ServerType.EMS)) } - @OnClick(R.id.loginServerChoiceOther) - fun selectOther() { + private fun selectOther() { loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Other)) } - @OnClick(R.id.loginServerIKnowMyIdSubmit) - fun loginWithMatrixId() { + private fun loginWithMatrixId() { loginViewModel.handle(LoginAction.UpdateSignMode(SignMode.SignInWithMatrixId)) } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt index 1915cdd204..7a4d60a2bd 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt @@ -23,7 +23,6 @@ import android.view.inputmethod.EditorInfo import android.widget.ArrayAdapter import androidx.core.view.isInvisible import androidx.core.view.isVisible -import butterknife.OnClick import com.google.android.material.textfield.TextInputLayout import com.jakewharton.rxbinding3.widget.textChanges import im.vector.app.BuildConfig @@ -46,9 +45,16 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + setupViews() setupHomeServerField() } + private fun setupViews() { + loginServerUrlFormLearnMore.setOnClickListener { learnMore() } + loginServerUrlFormClearHistory.setOnClickListener { clearHistory() } + loginServerUrlFormSubmit.setOnClickListener { submit() } + } + private fun setupHomeServerField() { loginServerUrlFormHomeServerUrl.textChanges() .subscribe { @@ -86,7 +92,7 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_common_notice) } } - val completions = state.knownCustomHomeServersUrls + if (BuildConfig.DEBUG) listOf("http://10.0.2.2:8080") else emptyList() + val completions = state.knownCustomHomeServersUrls + if (BuildConfig.DEBUG) listOf("http://10.0.2.2:8080") else emptyList() loginServerUrlFormHomeServerUrl.setAdapter(ArrayAdapter( requireContext(), R.layout.item_completion_homeserver, @@ -97,13 +103,11 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() ?: TextInputLayout.END_ICON_NONE } - @OnClick(R.id.loginServerUrlFormLearnMore) - fun learnMore() { + private fun learnMore() { openUrlInChromeCustomTab(requireActivity(), null, EMS_LINK) } - @OnClick(R.id.loginServerUrlFormClearHistory) - fun clearHistory() { + private fun clearHistory() { loginViewModel.handle(LoginAction.ClearHomeServerHistory) } @@ -112,8 +116,7 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() } @SuppressLint("SetTextI18n") - @OnClick(R.id.loginServerUrlFormSubmit) - fun submit() { + private fun submit() { cleanupUi() // Static check of homeserver url, empty, malformed, etc. diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt index ec931f89a2..36ef6eef61 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt @@ -16,8 +16,9 @@ package im.vector.app.features.login +import android.os.Bundle +import android.view.View import androidx.core.view.isVisible -import butterknife.OnClick import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.toReducedUrl @@ -31,6 +32,17 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLogi override fun getLayoutResId() = R.layout.fragment_login_signup_signin_selection + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupViews() + } + + private fun setupViews() { + loginSignupSigninSubmit.setOnClickListener { submit() } + loginSignupSigninSignIn.setOnClickListener { signIn() } + } + private fun setupUi(state: LoginViewState) { when (state.serverType) { ServerType.MatrixOrg -> { @@ -39,18 +51,18 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLogi loginSignupSigninTitle.text = getString(R.string.login_connect_to, state.homeServerUrl.toReducedUrl()) loginSignupSigninText.text = getString(R.string.login_server_matrix_org_text) } - ServerType.EMS -> { + ServerType.EMS -> { loginSignupSigninServerIcon.setImageResource(R.drawable.ic_logo_element_matrix_services) loginSignupSigninServerIcon.isVisible = true loginSignupSigninTitle.text = getString(R.string.login_connect_to_modular) loginSignupSigninText.text = state.homeServerUrl.toReducedUrl() } - ServerType.Other -> { + ServerType.Other -> { loginSignupSigninServerIcon.isVisible = false loginSignupSigninTitle.text = getString(R.string.login_server_other_title) loginSignupSigninText.text = getString(R.string.login_connect_to, state.homeServerUrl.toReducedUrl()) } - ServerType.Unknown -> Unit /* Should not happen */ + ServerType.Unknown -> Unit /* Should not happen */ } when (state.loginMode) { @@ -86,18 +98,15 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLogi } } - @OnClick(R.id.loginSignupSigninSubmit) - fun submit() = withState(loginViewModel) { state -> + private fun submit() = withState(loginViewModel) { state -> if (state.loginMode is LoginMode.Sso) { openInCustomTab(state.getSsoUrl(null)) } else { loginViewModel.handle(LoginAction.UpdateSignMode(SignMode.SignUp)) } - Unit } - @OnClick(R.id.loginSignupSigninSignIn) - fun signIn() { + private fun signIn() { loginViewModel.handle(LoginAction.UpdateSignMode(SignMode.SignIn)) } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt index fe0c36efc6..7cb3e30810 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt @@ -16,8 +16,10 @@ package im.vector.app.features.login -import butterknife.OnClick +import android.os.Bundle +import android.view.View import im.vector.app.R +import kotlinx.android.synthetic.main.fragment_login_splash.* import javax.inject.Inject /** @@ -27,8 +29,17 @@ class LoginSplashFragment @Inject constructor() : AbstractLoginFragment() { override fun getLayoutResId() = R.layout.fragment_login_splash - @OnClick(R.id.loginSplashSubmit) - fun getStarted() { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupViews() + } + + private fun setupViews() { + loginSplashSubmit.setOnClickListener { getStarted() } + } + + private fun getStarted() { loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OpenServerSelection)) } diff --git a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt index 624167dd91..8561b1035a 100755 --- a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt @@ -19,7 +19,6 @@ package im.vector.app.features.login.terms import android.os.Bundle import android.os.Parcelable import android.view.View -import butterknife.OnClick import com.airbnb.mvrx.args import im.vector.app.R import im.vector.app.core.extensions.cleanup @@ -55,6 +54,8 @@ class LoginTermsFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + setupViews() loginTermsPolicyList.configureWith(policyController) policyController.listener = this @@ -68,6 +69,10 @@ class LoginTermsFragment @Inject constructor( loginTermsViewState = LoginTermsViewState(list) } + private fun setupViews() { + loginTermsSubmit.setOnClickListener { submit() } + } + override fun onDestroyView() { loginTermsPolicyList.cleanup() policyController.listener = null @@ -99,8 +104,7 @@ class LoginTermsFragment @Inject constructor( } } - @OnClick(R.id.loginTermsSubmit) - internal fun submit() { + private fun submit() { loginViewModel.handle(LoginAction.AcceptTerms) } diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt index 3f38e4ef15..830f49f92f 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt @@ -20,8 +20,7 @@ import android.view.Menu import android.view.MenuItem import android.widget.Toast import androidx.core.view.isVisible -import butterknife.OnCheckedChanged -import butterknife.OnTextChanged +import androidx.core.widget.doOnTextChanged import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.platform.VectorBaseActivity @@ -43,6 +42,7 @@ class BugReportActivity : VectorBaseActivity() { override fun initUiAndData() { configureToolbar(bugReportToolbar) + setupViews() if (bugReporter.screenshot != null) { bug_report_screenshot_preview.setImageBitmap(bugReporter.screenshot) @@ -78,6 +78,11 @@ class BugReportActivity : VectorBaseActivity() { } } + private fun setupViews() { + bug_report_edit_text.doOnTextChanged { _, _, _, _ -> textChanged() } + bug_report_button_include_screenshot.setOnCheckedChangeListener { _, _ -> onSendScreenshotChanged() } + } + override fun getMenuRes() = R.menu.bug_report override fun onPrepareOptionsMenu(menu: Menu): Boolean { @@ -186,12 +191,10 @@ class BugReportActivity : VectorBaseActivity() { * UI Event * ========================================================================================== */ - @OnTextChanged(R.id.bug_report_edit_text) - internal fun textChanged() { + private fun textChanged() { bug_report_text_input_layout.error = null } - @OnCheckedChanged(R.id.bug_report_button_include_screenshot) internal fun onSendScreenshotChanged() { bug_report_screenshot_preview.isVisible = bug_report_button_include_screenshot.isChecked && bugReporter.screenshot != null } diff --git a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt index adb87a3bc5..c04fe8153b 100644 --- a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt +++ b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt @@ -18,11 +18,12 @@ package im.vector.app.features.signout.hard import android.content.Context import android.content.Intent -import butterknife.OnClick +import android.os.Bundle import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs +import kotlinx.android.synthetic.main.activity_signed_out.* import org.matrix.android.sdk.api.failure.GlobalError import timber.log.Timber @@ -33,8 +34,17 @@ class SignedOutActivity : VectorBaseActivity() { override fun getLayoutRes() = R.layout.activity_signed_out - @OnClick(R.id.signedOutSubmit) - fun submit() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setupViews() + } + + private fun setupViews() { + signedOutSubmit.setOnClickListener { submit() } + } + + private fun submit() { // All is already cleared when we are here MainActivity.restartApp(this, MainActivityArgs()) } diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt index 45ac9e7b1d..e1840fe687 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt @@ -16,10 +16,11 @@ package im.vector.app.features.widgets.permissions import android.content.DialogInterface +import android.os.Bundle import android.text.Spannable import android.text.SpannableStringBuilder import android.text.style.BulletSpan -import butterknife.OnClick +import android.view.View import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState @@ -50,6 +51,17 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() { // Use this if you don't need the full activity view model var directListener: ((Boolean) -> Unit)? = null + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupViews() + } + + private fun setupViews() { + widgetPermissionDecline.setOnClickListener { doDecline() } + widgetPermissionContinue.setOnClickListener { doAccept() } + } + override fun invalidate() = withState(viewModel) { state -> super.invalidate() val permissionData = state.permissionData() ?: return@withState @@ -76,16 +88,14 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() { widgetPermissionSharedInfo.text = infoBuilder } - @OnClick(R.id.widgetPermissionDecline) - fun doDecline() { + private fun doDecline() { viewModel.handle(RoomWidgetPermissionActions.BlockWidget) directListener?.invoke(false) // optimistic dismiss dismiss() } - @OnClick(R.id.widgetPermissionContinue) - fun doAccept() { + private fun doAccept() { viewModel.handle(RoomWidgetPermissionActions.AllowWidget) directListener?.invoke(true) // optimistic dismiss From 75ec9ba3d9623d1bc5ce292d75baf42280b2e40b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 15 Dec 2020 20:32:26 +0100 Subject: [PATCH 002/224] Reduce dependency on Butterknife: remove usage of @BindView --- .../app/features/debug/TestLinkifyActivity.kt | 18 +--- .../core/platform/SimpleFragmentActivity.kt | 14 +--- .../app/core/platform/VectorBaseActivity.kt | 21 +---- .../VectorBaseBottomSheetDialogFragment.kt | 10 +-- .../app/core/platform/VectorBaseFragment.kt | 10 +-- .../core/ui/bottomsheet/BottomSheetGeneric.kt | 9 +- .../app/core/ui/views/KeysBackupBanner.kt | 58 +++++-------- .../app/core/ui/views/PasswordStrengthBar.kt | 83 ++++++------------- .../app/features/call/CallControlsView.kt | 33 ++------ .../app/features/call/VectorCallActivity.kt | 13 +-- .../KeysBackupRestoreFromKeyFragment.kt | 11 +-- ...KeysBackupRestoreFromPassphraseFragment.kt | 27 ++---- .../KeysBackupRestoreSuccessFragment.kt | 8 -- .../setup/KeysBackupSetupStep1Fragment.kt | 11 +-- .../setup/KeysBackupSetupStep2Fragment.kt | 53 +++--------- .../setup/KeysBackupSetupStep3Fragment.kt | 19 +---- .../verification/VerificationBottomSheet.kt | 13 +-- .../vector/app/features/home/HomeActivity.kt | 4 +- .../home/room/detail/RoomDetailFragment.kt | 4 +- .../room/detail/composer/TextComposerView.kt | 32 +------ .../DisplayReadReceiptsBottomSheet.kt | 9 +- .../action/MessageActionsBottomSheet.kt | 14 ++-- .../edithistory/ViewEditHistoryBottomSheet.kt | 9 +- .../timeline/item/PollResultLineView.kt | 25 ++---- .../reactions/ViewReactionsBottomSheet.kt | 9 +- .../detail/timeline/url/PreviewUrlView.kt | 39 +++------ .../detail/widget/RoomWidgetsBottomSheet.kt | 9 +- .../RoomListQuickActionsBottomSheet.kt | 9 +- .../createroom/CreateRoomFragment.kt | 4 +- .../devices/DeviceListFragment.kt | 12 +-- .../devices/DeviceTrustInfoActionFragment.kt | 12 +-- .../roomprofile/RoomProfileFragment.kt | 4 +- .../roomprofile/alias/RoomAliasFragment.kt | 4 +- .../alias/detail/RoomAliasBottomSheet.kt | 9 +- .../settings/RoomSettingsFragment.kt | 4 +- ...ttingsNotificationsTroubleshootFragment.kt | 65 +++++---------- .../DeviceVerificationInfoBottomSheet.kt | 9 +- .../devices/VectorSettingsDevicesFragment.kt | 4 +- .../VectorSettingsIgnoredUsersFragment.kt | 4 +- ...ficationTroubleshootRecyclerViewAdapter.kt | 82 +++++++----------- .../signout/SignOutBottomSheetActionButton.kt | 32 ++----- .../SignOutBottomSheetDialogFragment.kt | 42 ++-------- vector/src/main/res/layout/activity.xml | 2 +- vector/src/main/res/layout/activity_call.xml | 8 +- vector/src/main/res/layout/activity_home.xml | 2 +- .../main/res/layout/activity_room_detail.xml | 2 +- .../src/main/res/layout/activity_simple.xml | 2 +- .../res/layout/activity_vector_settings.xml | 2 +- .../layout/bottom_sheet_logout_and_backup.xml | 10 +-- .../res/layout/bottom_sheet_verification.xml | 14 ++-- .../src/main/res/layout/composer_layout.xml | 16 ++-- ...composer_layout_constraint_set_compact.xml | 26 +++--- ...omposer_layout_constraint_set_expanded.xml | 46 +++++----- .../fragment_keys_backup_restore_from_key.xml | 10 +-- ...nt_keys_backup_restore_from_passphrase.xml | 4 +- .../fragment_keys_backup_restore_success.xml | 8 +- .../fragment_keys_backup_setup_step1.xml | 6 +- .../fragment_keys_backup_setup_step2.xml | 10 +-- .../fragment_keys_backup_setup_step3.xml | 4 +- .../res/layout/fragment_matrix_profile.xml | 2 +- .../res/layout/merge_overlay_waiting_view.xml | 6 +- .../main/res/layout/view_call_controls.xml | 12 +-- 62 files changed, 318 insertions(+), 735 deletions(-) diff --git a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt index fd28aabd49..8b7a431435 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt @@ -19,28 +19,18 @@ package im.vector.app.features.debug import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity -import androidx.coordinatorlayout.widget.CoordinatorLayout -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R +import kotlinx.android.synthetic.debug.activity_test_linkify.* class TestLinkifyActivity : AppCompatActivity() { - @BindView(R.id.test_linkify_content_view) - lateinit var scrollContent: LinearLayout - - @BindView(R.id.test_linkify_coordinator) - lateinit var coordinatorLayout: CoordinatorLayout - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_test_linkify) - ButterKnife.bind(this) - scrollContent.removeAllViews() + test_linkify_content_view.removeAllViews() listOf( "https://www.html5rocks.com/en/tutorials/webrtc/basics/ |", @@ -89,7 +79,7 @@ class TestLinkifyActivity : AppCompatActivity() { ) .forEach { textContent -> val item = LayoutInflater.from(this) - .inflate(R.layout.item_test_linkify, scrollContent, false) + .inflate(R.layout.item_test_linkify, test_linkify_content_view, false) item.findViewById(R.id.test_linkify_auto_text) ?.apply { @@ -125,7 +115,7 @@ class TestLinkifyActivity : AppCompatActivity() { // TODO Call VectorLinkify.addLinks(text) } - scrollContent.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) + test_linkify_content_view.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) } } } diff --git a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt index cfb3e3b656..76baf347f9 100644 --- a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt @@ -15,17 +15,14 @@ */ package im.vector.app.core.platform -import android.view.View -import android.widget.ProgressBar -import android.widget.TextView import androidx.annotation.CallSuper import androidx.core.view.isGone import androidx.core.view.isVisible -import butterknife.BindView import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.hideKeyboard import kotlinx.android.synthetic.main.activity.* +import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* import org.matrix.android.sdk.api.session.Session import javax.inject.Inject @@ -36,15 +33,6 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() { override fun getLayoutRes() = R.layout.activity - @BindView(R.id.waiting_view_status_circular_progress) - lateinit var waitingCircularProgress: View - - @BindView(R.id.waiting_view_status_text) - lateinit var waitingStatusText: TextView - - @BindView(R.id.waiting_view_status_horizontal_progress) - lateinit var waitingHorizontalProgress: ProgressBar - @Inject lateinit var session: Session @CallSuper diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index f895b2014f..4006137ee9 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -30,20 +30,15 @@ import androidx.annotation.CallSuper import androidx.annotation.LayoutRes import androidx.annotation.MainThread import androidx.annotation.MenuRes -import androidx.annotation.Nullable import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar -import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentFactory import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider -import butterknife.BindView -import butterknife.ButterKnife -import butterknife.Unbinder import com.airbnb.mvrx.MvRx import com.bumptech.glide.util.Util import com.google.android.material.snackbar.Snackbar @@ -84,21 +79,13 @@ import im.vector.app.receivers.DebugReceiver import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable +import kotlinx.android.synthetic.main.activity.* import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.failure.GlobalError import timber.log.Timber import kotlin.system.measureTimeMillis abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { - /* ========================================================================================== - * UI - * ========================================================================================== */ - - @Nullable - @JvmField - @BindView(R.id.vector_coordinator_layout) - var coordinatorLayout: CoordinatorLayout? = null - /* ========================================================================================== * View model * ========================================================================================== */ @@ -139,8 +126,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { // Filter for multiple invalid token error private var mainActivityStarted = false - private var unBinder: Unbinder? = null - private var savedInstanceState: Bundle? = null // For debug only @@ -229,8 +214,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { setContentView(getLayoutRes()) } - unBinder = ButterKnife.bind(this) - this.savedInstanceState = savedInstanceState initUiAndData() @@ -308,8 +291,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { override fun onDestroy() { super.onDestroy() Timber.i("onDestroy Activity ${javaClass.simpleName}") - unBinder?.unbind() - unBinder = null uiDisposables.dispose() } diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt index e674c277aa..74e9afb651 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt @@ -27,8 +27,6 @@ import android.widget.FrameLayout import androidx.annotation.CallSuper import androidx.annotation.LayoutRes import androidx.lifecycle.ViewModelProvider -import butterknife.ButterKnife -import butterknife.Unbinder import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.MvRxView import com.airbnb.mvrx.MvRxViewId @@ -61,8 +59,6 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment() @LayoutRes abstract fun getLayoutResId(): Int - private var unBinder: Unbinder? = null - /* ========================================================================================== * View model * ========================================================================================== */ @@ -106,16 +102,12 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment() } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(getLayoutResId(), container, false) - unBinder = ButterKnife.bind(this, view) - return view + return inflater.inflate(getLayoutResId(), container, false) } @CallSuper override fun onDestroyView() { super.onDestroyView() - unBinder?.unbind() - unBinder = null uiDisposables.clear() } diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt index cd38f5aeaa..ffaee5075f 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt @@ -33,8 +33,6 @@ import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.Toolbar import androidx.lifecycle.ViewModelProvider -import butterknife.ButterKnife -import butterknife.Unbinder import com.airbnb.mvrx.BaseMvRxFragment import com.airbnb.mvrx.MvRx import com.bumptech.glide.util.Util.assertMainThread @@ -50,14 +48,12 @@ import im.vector.app.features.navigation.Navigator import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable +import kotlinx.android.synthetic.main.activity.* import timber.log.Timber import java.util.concurrent.TimeUnit abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { - // Butterknife unbinder - private var mUnBinder: Unbinder? = null - protected val vectorBaseActivity: VectorBaseActivity by lazy { activity as VectorBaseActivity } @@ -125,7 +121,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { @CallSuper override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - mUnBinder = ButterKnife.bind(this, view) + Timber.i("onViewCreated Fragment ${javaClass.simpleName}") } open fun showLoading(message: CharSequence?) { @@ -140,8 +136,6 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { override fun onDestroyView() { super.onDestroyView() Timber.i("onDestroyView Fragment ${javaClass.simpleName}") - mUnBinder?.unbind() - mUnBinder = null uiDisposables.clear() } diff --git a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt index da136fb072..ab4a781aab 100644 --- a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt +++ b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt @@ -20,11 +20,11 @@ import android.os.Bundle import android.view.View import androidx.annotation.CallSuper import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* import javax.inject.Inject /** @@ -36,9 +36,6 @@ abstract class BottomSheetGeneric { - bar1.setBackgroundColor(colorBackground) - bar2.setBackgroundColor(colorBackground) - bar3.setBackgroundColor(colorBackground) - bar4.setBackgroundColor(colorBackground) + password_strength_bar_1.setBackgroundColor(colorBackground) + password_strength_bar_2.setBackgroundColor(colorBackground) + password_strength_bar_3.setBackgroundColor(colorBackground) + password_strength_bar_4.setBackgroundColor(colorBackground) } 1 -> { - bar1.setBackgroundColor(colorWeak) - bar2.setBackgroundColor(colorBackground) - bar3.setBackgroundColor(colorBackground) - bar4.setBackgroundColor(colorBackground) + password_strength_bar_1.setBackgroundColor(colorWeak) + password_strength_bar_2.setBackgroundColor(colorBackground) + password_strength_bar_3.setBackgroundColor(colorBackground) + password_strength_bar_4.setBackgroundColor(colorBackground) } 2 -> { - bar1.setBackgroundColor(colorLow) - bar2.setBackgroundColor(colorLow) - bar3.setBackgroundColor(colorBackground) - bar4.setBackgroundColor(colorBackground) + password_strength_bar_1.setBackgroundColor(colorLow) + password_strength_bar_2.setBackgroundColor(colorLow) + password_strength_bar_3.setBackgroundColor(colorBackground) + password_strength_bar_4.setBackgroundColor(colorBackground) } 3 -> { - bar1.setBackgroundColor(colorOk) - bar2.setBackgroundColor(colorOk) - bar3.setBackgroundColor(colorOk) - bar4.setBackgroundColor(colorBackground) + password_strength_bar_1.setBackgroundColor(colorOk) + password_strength_bar_2.setBackgroundColor(colorOk) + password_strength_bar_3.setBackgroundColor(colorOk) + password_strength_bar_4.setBackgroundColor(colorBackground) } 4 -> { - bar1.setBackgroundColor(colorStrong) - bar2.setBackgroundColor(colorStrong) - bar3.setBackgroundColor(colorStrong) - bar4.setBackgroundColor(colorStrong) + password_strength_bar_1.setBackgroundColor(colorStrong) + password_strength_bar_2.setBackgroundColor(colorStrong) + password_strength_bar_3.setBackgroundColor(colorStrong) + password_strength_bar_4.setBackgroundColor(colorStrong) } } } @@ -116,7 +88,6 @@ class PasswordStrengthBar @JvmOverloads constructor( LayoutInflater.from(context) .inflate(R.layout.view_password_strength_bar, this, true) orientation = HORIZONTAL - ButterKnife.bind(this) strength = 0 } } diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt index 4e46ace192..81cc077f03 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt @@ -18,13 +18,9 @@ package im.vector.app.features.call import android.content.Context import android.util.AttributeSet -import android.view.ViewGroup -import android.widget.ImageView import android.widget.LinearLayout import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R import kotlinx.android.synthetic.main.view_call_controls.view.* import org.matrix.android.sdk.api.session.call.CallState @@ -36,34 +32,15 @@ class CallControlsView @JvmOverloads constructor( var interactionListener: InteractionListener? = null - @BindView(R.id.ringingControls) - lateinit var ringingControls: ViewGroup - - @BindView(R.id.iv_icr_accept_call) - lateinit var ringingControlAccept: ImageView - - @BindView(R.id.iv_icr_end_call) - lateinit var ringingControlDecline: ImageView - - @BindView(R.id.connectedControls) - lateinit var connectedControls: ViewGroup - - @BindView(R.id.iv_mute_toggle) - lateinit var muteIcon: ImageView - - @BindView(R.id.iv_video_toggle) - lateinit var videoToggleIcon: ImageView - init { ConstraintLayout.inflate(context, R.layout.view_call_controls, this) // layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - ButterKnife.bind(this) - iv_icr_accept_call.setOnClickListener { acceptIncomingCall() } - iv_icr_end_call.setOnClickListener { declineIncomingCall() } + ringingControlAccept.setOnClickListener { acceptIncomingCall() } + ringingControlDecline.setOnClickListener { declineIncomingCall() } iv_end_call.setOnClickListener { endOngoingCall() } - iv_mute_toggle.setOnClickListener { toggleMute() } - iv_video_toggle.setOnClickListener { toggleVideo() } + muteIcon.setOnClickListener { toggleMute() } + videoToggleIcon.setOnClickListener { toggleVideo() } iv_leftMiniControl.setOnClickListener { returnToChat() } iv_more.setOnClickListener { moreControlOption() } } @@ -132,7 +109,7 @@ class CallControlsView @JvmOverloads constructor( if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) { ringingControls.isVisible = false connectedControls.isVisible = true - iv_video_toggle.isVisible = state.isVideoCall + videoToggleIcon.isVisible = state.isVideoCall } else { ringingControls.isVisible = true ringingControlAccept.isVisible = false diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 9ab39bc0a9..aee882fedf 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -32,7 +32,6 @@ import androidx.core.view.ViewCompat import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.core.view.updatePadding -import butterknife.BindView import com.airbnb.mvrx.Fail import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.viewModel @@ -58,7 +57,6 @@ import org.matrix.android.sdk.api.session.call.TurnServerResponse import org.webrtc.EglBase import org.webrtc.PeerConnection import org.webrtc.RendererCommon -import org.webrtc.SurfaceViewRenderer import timber.log.Timber import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -90,15 +88,6 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis @Inject lateinit var viewModelFactory: VectorCallViewModel.Factory - @BindView(R.id.pip_video_view) - lateinit var pipRenderer: SurfaceViewRenderer - - @BindView(R.id.fullscreen_video_view) - lateinit var fullscreenRenderer: SurfaceViewRenderer - - @BindView(R.id.callControls) - lateinit var callControlsView: CallControlsView - private var rootEglBase: EglBase? = null var systemUiVisibility = false @@ -259,7 +248,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis if (callArgs.isVideoCall) { callVideoGroup.isVisible = true callInfoGroup.isVisible = false - pip_video_view.isVisible = !state.isVideoCaptureInError + pipRenderer.isVisible = !state.isVideoCaptureInError } else { callVideoGroup.isInvisible = true callInfoGroup.isVisible = true diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt index 1db7797560..7d2ec839d4 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt @@ -19,11 +19,8 @@ import android.app.Activity import android.os.Bundle import android.view.View import android.view.inputmethod.EditorInfo -import android.widget.EditText import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer -import butterknife.BindView -import com.google.android.material.textfield.TextInputLayout import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment @@ -40,12 +37,6 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() private lateinit var viewModel: KeysBackupRestoreFromKeyViewModel private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel - @BindView(R.id.keys_backup_key_enter_til) - lateinit var mKeyInputLayout: TextInputLayout - - @BindView(R.id.keys_restore_key_enter_edittext) - lateinit var mKeyTextEdit: EditText - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromKeyViewModel::class.java) @@ -66,7 +57,7 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() keys_restore_button.setOnClickListener { onRestoreFromKey() } keys_backup_import.setOnClickListener { onImport() } - keys_restore_key_enter_edittext.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) } + mKeyTextEdit.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) } } private fun onRestoreKeyTextEditChange(s: CharSequence?) { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt index bffed5c1bb..95151b3551 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt @@ -20,14 +20,9 @@ import android.text.SpannableString import android.text.style.ClickableSpan import android.view.View import android.view.inputmethod.EditorInfo -import android.widget.EditText -import android.widget.ImageView -import android.widget.TextView import androidx.core.text.set import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer -import butterknife.BindView -import com.google.android.material.textfield.TextInputLayout import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment @@ -41,18 +36,6 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase private lateinit var viewModel: KeysBackupRestoreFromPassphraseViewModel private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel - @BindView(R.id.keys_backup_passphrase_enter_til) - lateinit var mPassphraseInputLayout: TextInputLayout - - @BindView(R.id.keys_backup_passphrase_enter_edittext) - lateinit var mPassphraseTextEdit: EditText - - @BindView(R.id.keys_backup_view_show_password) - lateinit var mPassphraseReveal: ImageView - - @BindView(R.id.keys_backup_passphrase_help_with_link) - lateinit var helperTextWithLink: TextView - private fun toggleVisibilityMode() { viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false) } @@ -64,18 +47,18 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java) viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue -> - mPassphraseInputLayout.error = newValue + keys_backup_passphrase_enter_til.error = newValue }) helperTextWithLink.text = spannableStringForHelperText() viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer { val shouldBeVisible = it ?: false - mPassphraseTextEdit.showPassword(shouldBeVisible) - mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) + keys_backup_passphrase_enter_edittext.showPassword(shouldBeVisible) + keys_backup_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) }) - mPassphraseTextEdit.setOnEditorActionListener { _, actionId, _ -> + keys_backup_passphrase_enter_edittext.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE) { onRestoreBackup() return@setOnEditorActionListener true @@ -84,7 +67,7 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase } keys_backup_view_show_password.setOnClickListener { toggleVisibilityMode() } - keys_backup_passphrase_help_with_link.setOnClickListener { onUseRecoveryKey() } + helperTextWithLink.setOnClickListener { onUseRecoveryKey() } keys_backup_restore_with_passphrase_submit.setOnClickListener { onRestoreBackup() } keys_backup_passphrase_enter_edittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt index 710bd97bbd..902f376ec4 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt @@ -17,9 +17,7 @@ package im.vector.app.features.crypto.keysbackup.restore import android.os.Bundle import android.view.View -import android.widget.TextView import androidx.core.view.isVisible -import butterknife.BindView import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.LiveEvent @@ -30,12 +28,6 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_success - @BindView(R.id.keys_backup_restore_success) - lateinit var mSuccessText: TextView - - @BindView(R.id.keys_backup_restore_success_info) - lateinit var mSuccessDetailsText: TextView - private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt index 12017a3562..c3d5c56189 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt @@ -18,10 +18,7 @@ package im.vector.app.features.crypto.keysbackup.setup import android.os.Bundle import android.view.View -import android.widget.Button -import android.widget.TextView import androidx.lifecycle.Observer -import butterknife.BindView import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.LiveEvent @@ -34,12 +31,6 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() private lateinit var viewModel: KeysBackupSetupSharedViewModel - @BindView(R.id.keys_backup_setup_step1_advanced) - lateinit var advancedOptionText: TextView - - @BindView(R.id.keys_backup_setup_step1_manualExport) - lateinit var manualExportButton: Button - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -53,7 +44,7 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() }) keys_backup_setup_step1_button.setOnClickListener { onButtonClick() } - keys_backup_setup_step1_manualExport.setOnClickListener { onManualExportClick() } + manualExportButton.setOnClickListener { onManualExportClick() } } private fun onButtonClick() { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt index 4f3a73e14b..93f3b71ced 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt @@ -17,21 +17,15 @@ package im.vector.app.features.crypto.keysbackup.setup import android.os.Bundle import android.view.View -import android.view.ViewGroup import android.view.inputmethod.EditorInfo -import android.widget.EditText -import android.widget.ImageView import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer import androidx.lifecycle.viewModelScope import androidx.transition.TransitionManager -import butterknife.BindView -import com.google.android.material.textfield.TextInputLayout import com.nulabinc.zxcvbn.Zxcvbn import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment -import im.vector.app.core.ui.views.PasswordStrengthBar import im.vector.app.features.settings.VectorLocale import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step2.* import kotlinx.coroutines.Dispatchers @@ -42,31 +36,10 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step2 - @BindView(R.id.keys_backup_root) - lateinit var rootGroup: ViewGroup - - @BindView(R.id.keys_backup_passphrase_enter_edittext) - lateinit var mPassphraseTextEdit: EditText - - @BindView(R.id.keys_backup_passphrase_enter_til) - lateinit var mPassphraseInputLayout: TextInputLayout - - @BindView(R.id.keys_backup_view_show_password) - lateinit var mPassphraseReveal: ImageView - - @BindView(R.id.keys_backup_passphrase_confirm_edittext) - lateinit var mPassphraseConfirmTextEdit: EditText - - @BindView(R.id.keys_backup_passphrase_confirm_til) - lateinit var mPassphraseConfirmInputLayout: TextInputLayout - - @BindView(R.id.keys_backup_passphrase_security_progress) - lateinit var mPassphraseProgressLevel: PasswordStrengthBar - private val zxcvbn = Zxcvbn() private fun onPassphraseChanged() { - viewModel.passphrase.value = mPassphraseTextEdit.text.toString() + viewModel.passphrase.value = keys_backup_passphrase_enter_edittext.text.toString() viewModel.confirmPassphraseError.value = null } @@ -94,7 +67,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() viewModel.passwordStrength.observe(viewLifecycleOwner, Observer { strength -> if (strength == null) { mPassphraseProgressLevel.strength = 0 - mPassphraseInputLayout.error = null + keys_backup_passphrase_enter_til.error = null } else { val score = strength.score mPassphraseProgressLevel.strength = score @@ -102,15 +75,15 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() if (score in 1..3) { val warning = strength.feedback?.getWarning(VectorLocale.applicationLocale) if (warning != null) { - mPassphraseInputLayout.error = warning + keys_backup_passphrase_enter_til.error = warning } val suggestions = strength.feedback?.getSuggestions(VectorLocale.applicationLocale) if (suggestions != null) { - mPassphraseInputLayout.error = suggestions.firstOrNull() + keys_backup_passphrase_enter_til.error = suggestions.firstOrNull() } } else { - mPassphraseInputLayout.error = null + keys_backup_passphrase_enter_til.error = null } } }) @@ -128,24 +101,24 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() } }) - mPassphraseTextEdit.setText(viewModel.passphrase.value) + keys_backup_passphrase_enter_edittext.setText(viewModel.passphrase.value) viewModel.passphraseError.observe(viewLifecycleOwner, Observer { - TransitionManager.beginDelayedTransition(rootGroup) - mPassphraseInputLayout.error = it + TransitionManager.beginDelayedTransition(keys_backup_root) + keys_backup_passphrase_enter_til.error = it }) mPassphraseConfirmTextEdit.setText(viewModel.confirmPassphrase.value) viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer { val shouldBeVisible = it ?: false - mPassphraseTextEdit.showPassword(shouldBeVisible) + keys_backup_passphrase_enter_edittext.showPassword(shouldBeVisible) mPassphraseConfirmTextEdit.showPassword(shouldBeVisible) - mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) + keys_backup_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) }) viewModel.confirmPassphraseError.observe(viewLifecycleOwner, Observer { - TransitionManager.beginDelayedTransition(rootGroup) + TransitionManager.beginDelayedTransition(keys_backup_root) mPassphraseConfirmInputLayout.error = it }) @@ -163,8 +136,8 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() keys_backup_setup_step2_button.setOnClickListener { doNext() } keys_backup_setup_step2_skip_button.setOnClickListener { skipPassphrase() } - keys_backup_passphrase_enter_edittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged()} - keys_backup_passphrase_confirm_edittext.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged()} + keys_backup_passphrase_enter_edittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() } + mPassphraseConfirmTextEdit.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() } } private fun toggleVisibilityMode() { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index c686b23b53..94c9b68606 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -19,14 +19,12 @@ import android.app.Activity import android.net.Uri import android.os.Bundle import android.view.View -import android.widget.Button import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.lifecycle.Observer import arrow.core.Try -import butterknife.BindView import com.google.android.material.bottomsheet.BottomSheetDialog import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult @@ -50,15 +48,6 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step3 - @BindView(R.id.keys_backup_setup_step3_button) - lateinit var mFinishButton: Button - - @BindView(R.id.keys_backup_recovery_key_text) - lateinit var mRecoveryKeyTextView: TextView - - @BindView(R.id.keys_backup_setup_step3_line2_text) - lateinit var mRecoveryKeyLabel2TextView: TextView - private lateinit var viewModel: KeysBackupSetupSharedViewModel override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -73,7 +62,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase) mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title_no_passphrase) - mRecoveryKeyTextView.text = viewModel.recoveryKey.value!! + keys_backup_recovery_key_text.text = viewModel.recoveryKey.value!! .replace(" ", "") .chunked(16) .joinToString("\n") { @@ -81,11 +70,11 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() .chunked(4) .joinToString(" ") } - mRecoveryKeyTextView.isVisible = true + keys_backup_recovery_key_text.isVisible = true } else { mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2) mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title) - mRecoveryKeyTextView.isVisible = false + keys_backup_recovery_key_text.isVisible = false } }) @@ -93,7 +82,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() } private fun setupViews() { - keys_backup_setup_step3_button.setOnClickListener { onFinishButtonClicked() } + mFinishButton.setOnClickListener { onFinishButtonClicked() } keys_backup_setup_step3_copy_button.setOnClickListener { onCopyButtonClicked() } keys_backup_recovery_key_text.setOnClickListener { onRecoveryKeyClicked() } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt index a9b76366df..6a9e89f4f5 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt @@ -21,12 +21,9 @@ import android.os.Bundle import android.os.Parcelable import android.view.KeyEvent import android.view.View -import android.widget.ImageView -import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.fragment.app.Fragment -import butterknife.BindView import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -49,6 +46,7 @@ import im.vector.app.features.crypto.verification.request.VerificationRequestFra import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.settings.VectorSettingsActivity import kotlinx.android.parcel.Parcelize +import kotlinx.android.synthetic.main.bottom_sheet_verification.* import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME @@ -86,15 +84,6 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { injector.inject(this) } - @BindView(R.id.verificationRequestName) - lateinit var otherUserNameText: TextView - - @BindView(R.id.verificationRequestShield) - lateinit var otherUserShield: ImageView - - @BindView(R.id.verificationRequestAvatar) - lateinit var otherUserAvatarImageView: ImageView - override fun getLayoutResId() = R.layout.bottom_sheet_verification init { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index e1837ccb1b..d4aff21c40 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -204,13 +204,13 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet waiting_view.setOnClickListener { // block interactions } - waiting_view_status_horizontal_progress.apply { + waitingHorizontalProgress.apply { isIndeterminate = false max = 100 progress = status.percentProgress isVisible = true } - waiting_view_status_text.apply { + waitingStatusText.apply { text = getString(status.statusText) isVisible = true } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 45efe1e15a..1a7a7ec359 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -1295,8 +1295,8 @@ class RoomDetailFragment @Inject constructor( is Loading -> { // TODO Better handling progress vectorBaseActivity.showWaitingView() - vectorBaseActivity.waiting_view_status_text.visibility = View.VISIBLE - vectorBaseActivity.waiting_view_status_text.text = getString(R.string.joining_room) + vectorBaseActivity.waitingStatusText.visibility = View.VISIBLE + vectorBaseActivity.waitingStatusText.text = getString(R.string.joining_room) } is Success -> { navigator.openRoom(vectorBaseActivity, async()) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt index f232e9a65e..d48d994caa 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt @@ -21,9 +21,6 @@ import android.net.Uri import android.text.Editable import android.util.AttributeSet import android.view.ViewGroup -import android.widget.ImageButton -import android.widget.ImageView -import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.core.text.toSpannable @@ -33,8 +30,6 @@ import androidx.transition.Fade import androidx.transition.Transition import androidx.transition.TransitionManager import androidx.transition.TransitionSet -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R import kotlinx.android.synthetic.main.composer_layout.view.* import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel @@ -54,30 +49,6 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib var callback: Callback? = null - @BindView(R.id.composer_related_message_sender) - lateinit var composerRelatedMessageTitle: TextView - - @BindView(R.id.composer_related_message_preview) - lateinit var composerRelatedMessageContent: TextView - - @BindView(R.id.composer_related_message_avatar_view) - lateinit var composerRelatedMessageAvatar: ImageView - - @BindView(R.id.composer_related_message_action_image) - lateinit var composerRelatedMessageActionIcon: ImageView - - @BindView(R.id.composer_related_message_close) - lateinit var composerRelatedMessageCloseButton: ImageButton - - @BindView(R.id.composerEditText) - lateinit var composerEditText: ComposerEditText - - @BindView(R.id.composer_emoji) - lateinit var composerEmojiButton: ImageButton - - @BindView(R.id.composer_shield) - lateinit var composerShieldImageView: ImageView - private var currentConstraintSetId: Int = -1 private val animationDuration = 100L @@ -87,7 +58,6 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib init { inflate(context, R.layout.composer_layout, this) - ButterKnife.bind(this) collapse(false) composerEditText.callback = object : ComposerEditText.Callback { override fun onRichContentSelected(contentUri: Uri): Boolean { @@ -134,7 +104,7 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib ConstraintSet().also { it.clone(context, currentConstraintSetId) // in case shield is hidden, we will have glitch without this - it.getConstraint(R.id.composer_shield).propertySet.visibility = composerShieldImageView.visibility + it.getConstraint(R.id.composerShieldImageView).propertySet.visibility = composerShieldImageView.visibility it.applyTo(this) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt index 5fefc9aba8..bf3ee97f9e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt @@ -19,8 +19,6 @@ package im.vector.app.features.home.room.detail.readreceipts import android.os.Bundle import android.os.Parcelable import android.view.View -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.args import im.vector.app.R @@ -47,9 +45,6 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), Di @Inject lateinit var epoxyController: DisplayReadReceiptsController - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - private val displayReadReceiptArgs: DisplayReadReceiptArgs by args() private lateinit var sharedActionViewModel: MessageSharedActionViewModel @@ -63,14 +58,14 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), Di override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) - recyclerView.configureWith(epoxyController, hasFixedSize = false) + bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false) bottomSheetTitle.text = getString(R.string.seen_by) epoxyController.listener = this epoxyController.setData(displayReadReceiptArgs.readReceipts) } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() epoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt index f337f0ba5f..81e9ffd24e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt @@ -17,8 +17,6 @@ package im.vector.app.features.home.room.detail.timeline.action import android.os.Bundle import android.view.View -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -27,6 +25,7 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData +import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* import javax.inject.Inject /** @@ -37,9 +36,6 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message @Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory @Inject lateinit var messageActionsEpoxyController: MessageActionsEpoxyController - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - private val viewModel: MessageActionsViewModel by fragmentViewModel(MessageActionsViewModel::class) override val showExpanded = true @@ -55,12 +51,12 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) - recyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true) + bottomSheetRecyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true) messageActionsEpoxyController.listener = this } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() super.onDestroyView() } @@ -80,8 +76,8 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message if (eventAction is EventSharedAction.ReportContent) { // Toggle report menu // Enable item animation - if (recyclerView.itemAnimator == null) { - recyclerView.itemAnimator = MessageActionsAnimator() + if (bottomSheetRecyclerView.itemAnimator == null) { + bottomSheetRecyclerView.itemAnimator = MessageActionsAnimator() } viewModel.handle(MessageActionsAction.ToggleReportMenu) } else { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt index 080ccaea7c..7a6bb412cc 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt @@ -17,8 +17,6 @@ package im.vector.app.features.home.room.detail.timeline.edithistory import android.os.Bundle import android.view.View -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -43,9 +41,6 @@ class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() { @Inject lateinit var viewEditHistoryViewModelFactory: ViewEditHistoryViewModel.Factory @Inject lateinit var eventHtmlRenderer: EventHtmlRenderer - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - private val epoxyController by lazy { ViewEditHistoryEpoxyController(requireContext(), viewModel.dateFormatter, eventHtmlRenderer) } @@ -58,7 +53,7 @@ class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - recyclerView.configureWith( + bottomSheetRecyclerView.configureWith( epoxyController, showDivider = true, hasFixedSize = false) @@ -66,7 +61,7 @@ class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() { } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt index 83174792e2..be368682c1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt @@ -19,14 +19,11 @@ import android.content.Context import android.graphics.Typeface import android.util.AttributeSet import android.view.View -import android.widget.ImageView import android.widget.LinearLayout -import android.widget.TextView import androidx.core.content.withStyledAttributes -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide +import kotlinx.android.synthetic.main.item_timeline_event_poll_result_item.view.* class PollResultLineView @JvmOverloads constructor( context: Context, @@ -34,45 +31,35 @@ class PollResultLineView @JvmOverloads constructor( defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { - @BindView(R.id.pollResultItemLabel) - lateinit var labelTextView: TextView - - @BindView(R.id.pollResultItemPercent) - lateinit var percentTextView: TextView - - @BindView(R.id.pollResultItemSelectedIcon) - lateinit var selectedIcon: ImageView - var label: String? = null set(value) { field = value - labelTextView.setTextOrHide(value) + pollResultItemLabel.setTextOrHide(value) } var percent: String? = null set(value) { field = value - percentTextView.setTextOrHide(value) + pollResultItemPercent.setTextOrHide(value) } var optionSelected: Boolean = false set(value) { field = value - selectedIcon.visibility = if (value) View.VISIBLE else View.INVISIBLE + pollResultItemSelectedIcon.visibility = if (value) View.VISIBLE else View.INVISIBLE } var isWinner: Boolean = false set(value) { field = value // Text in main color - labelTextView.setTypeface(labelTextView.typeface, if (value) Typeface.BOLD else Typeface.NORMAL) - percentTextView.setTypeface(percentTextView.typeface, if (value) Typeface.BOLD else Typeface.NORMAL) + pollResultItemLabel.setTypeface(pollResultItemLabel.typeface, if (value) Typeface.BOLD else Typeface.NORMAL) + pollResultItemPercent.setTypeface(pollResultItemPercent.typeface, if (value) Typeface.BOLD else Typeface.NORMAL) } init { inflate(context, R.layout.item_timeline_event_poll_result_item, this) orientation = HORIZONTAL - ButterKnife.bind(this) context.withStyledAttributes(attrs, R.styleable.PollResultLineView) { label = getString(R.styleable.PollResultLineView_optionName) ?: "" diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt index 2e0d07aa67..c1d71f4162 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt @@ -18,8 +18,6 @@ package im.vector.app.features.home.room.detail.timeline.reactions import android.os.Bundle import android.view.View -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -45,9 +43,6 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReac @Inject lateinit var viewReactionsViewModelFactory: ViewReactionsViewModel.Factory private lateinit var sharedActionViewModel: MessageSharedActionViewModel - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - @Inject lateinit var epoxyController: ViewReactionsEpoxyController override fun injectWith(injector: ScreenComponent) { @@ -59,13 +54,13 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReac override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) - recyclerView.configureWith(epoxyController, hasFixedSize = false, showDivider = true) + bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false, showDivider = true) bottomSheetTitle.text = context?.getString(R.string.reactions) epoxyController.listener = this } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() epoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt index 9d8f438683..c69e47614c 100755 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt @@ -19,16 +19,13 @@ package im.vector.app.features.home.room.detail.timeline.url import android.content.Context import android.util.AttributeSet import android.view.View -import android.widget.ImageView -import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.media.ImageContentRenderer +import kotlinx.android.synthetic.main.url_preview.view.* import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.media.PreviewUrlData @@ -41,21 +38,6 @@ class PreviewUrlView @JvmOverloads constructor( defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener { - @BindView(R.id.url_preview_title) - lateinit var titleView: TextView - - @BindView(R.id.url_preview_image) - lateinit var imageView: ImageView - - @BindView(R.id.url_preview_description) - lateinit var descriptionView: TextView - - @BindView(R.id.url_preview_site) - lateinit var siteView: TextView - - @BindView(R.id.url_preview_close) - lateinit var closeView: View - var delegate: TimelineEventController.PreviewUrlCallback? = null init { @@ -106,10 +88,9 @@ class PreviewUrlView @JvmOverloads constructor( private fun setupView() { inflate(context, R.layout.url_preview, this) - ButterKnife.bind(this) setOnClickListener(this) - closeView.setOnClickListener { onCloseClick() } + url_preview_close.setOnClickListener { onCloseClick() } } private fun renderHidden() { @@ -123,19 +104,19 @@ class PreviewUrlView @JvmOverloads constructor( private fun renderData(previewUrlData: PreviewUrlData, imageContentRenderer: ImageContentRenderer) { isVisible = true - titleView.setTextOrHide(previewUrlData.title) - imageView.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, imageView) }.orFalse() - descriptionView.setTextOrHide(previewUrlData.description) - siteView.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title }) + url_preview_title.setTextOrHide(previewUrlData.title) + url_preview_image.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, url_preview_image) }.orFalse() + url_preview_description.setTextOrHide(previewUrlData.description) + url_preview_site.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title }) } /** * Hide all views that are not visible in all state */ private fun hideAll() { - titleView.isVisible = false - imageView.isVisible = false - descriptionView.isVisible = false - siteView.isVisible = false + url_preview_title.isVisible = false + url_preview_image.isVisible = false + url_preview_description.isVisible = false + url_preview_site.isVisible = false } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt index 923f9d8e2e..1799deae66 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt @@ -18,8 +18,6 @@ package im.vector.app.features.home.room.detail.widget import android.os.Bundle import android.view.View -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -45,9 +43,6 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget @Inject lateinit var colorProvider: ColorProvider @Inject lateinit var navigator: Navigator - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - private val roomDetailViewModel: RoomDetailViewModel by parentFragmentViewModel() override fun injectWith(injector: ScreenComponent) { @@ -58,7 +53,7 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - recyclerView.configureWith(epoxyController, hasFixedSize = false) + bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false) bottomSheetTitle.text = getString(R.string.active_widgets_title) bottomSheetTitle.textSize = 20f bottomSheetTitle.setTextColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)) @@ -69,7 +64,7 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() epoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt index f41104cae1..306e951ab8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt @@ -20,7 +20,6 @@ import android.os.Bundle import android.os.Parcelable import android.view.View import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -30,6 +29,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.features.navigation.Navigator import kotlinx.android.parcel.Parcelize +import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* import javax.inject.Inject @Parcelize @@ -57,9 +57,6 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R private val viewModel: RoomListQuickActionsViewModel by fragmentViewModel(RoomListQuickActionsViewModel::class) - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - override val showExpanded = true override fun injectWith(injector: ScreenComponent) { @@ -71,12 +68,12 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java) - recyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) + bottomSheetRecyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) roomListActionsEpoxyController.listener = this } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() roomListActionsEpoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index 204a99929b..f859009b13 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -90,8 +90,8 @@ class CreateRoomFragment @Inject constructor( } private fun setupWaitingView() { - waiting_view_status_text.isVisible = true - waiting_view_status_text.setText(R.string.create_room_in_progress) + waitingStatusText.isVisible = true + waitingStatusText.setText(R.string.create_room_in_progress) } override fun onDestroyView() { diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt index e9fdd15af4..342213fac0 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt @@ -18,8 +18,6 @@ package im.vector.app.features.roommemberprofile.devices import android.os.Bundle import android.view.View -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -27,6 +25,7 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter +import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import javax.inject.Inject @@ -39,13 +38,10 @@ class DeviceListFragment @Inject constructor( private val viewModel: DeviceListBottomSheetViewModel by parentFragmentViewModel(DeviceListBottomSheetViewModel::class) - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - recyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) - recyclerView.configureWith( + bottomSheetRecyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) + bottomSheetRecyclerView.configureWith( epoxyController, showDivider = false, hasFixedSize = false) @@ -53,7 +49,7 @@ class DeviceListFragment @Inject constructor( } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt index e31f3172e9..1b5e571519 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt @@ -18,8 +18,6 @@ package im.vector.app.features.roommemberprofile.devices import android.os.Bundle import android.view.View -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -27,6 +25,7 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter +import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import javax.inject.Inject @@ -39,13 +38,10 @@ class DeviceTrustInfoActionFragment @Inject constructor( private val viewModel: DeviceListBottomSheetViewModel by parentFragmentViewModel(DeviceListBottomSheetViewModel::class) - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - recyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) - recyclerView.configureWith( + bottomSheetRecyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) + bottomSheetRecyclerView.configureWith( epoxyController, showDivider = false, hasFixedSize = false) @@ -53,7 +49,7 @@ class DeviceTrustInfoActionFragment @Inject constructor( } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index bab64aebe9..628e3869b4 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -114,8 +114,8 @@ class RoomProfileFragment @Inject constructor( } private fun setupWaitingView() { - waiting_view_status_text.setText(R.string.please_wait) - waiting_view_status_text.isVisible = true + waitingStatusText.setText(R.string.please_wait) + waitingStatusText.isVisible = true } private fun setupLongClicks() { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt index 56c3e76828..689b057385 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt @@ -66,8 +66,8 @@ class RoomAliasFragment @Inject constructor( controller.callback = this setupToolbar(roomSettingsToolbar) roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) - waiting_view_status_text.setText(R.string.please_wait) - waiting_view_status_text.isVisible = true + waitingStatusText.setText(R.string.please_wait) + waitingStatusText.isVisible = true viewModel.observeViewEvents { when (it) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt index 86702d1507..265abe5862 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt @@ -20,7 +20,6 @@ import android.os.Bundle import android.os.Parcelable import android.view.View import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -29,6 +28,7 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import kotlinx.android.parcel.Parcelize +import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* import javax.inject.Inject @Parcelize @@ -52,9 +52,6 @@ class RoomAliasBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomAliasBot private val viewModel: RoomAliasBottomSheetViewModel by fragmentViewModel(RoomAliasBottomSheetViewModel::class) - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - override val showExpanded = true override fun injectWith(injector: ScreenComponent) { @@ -66,12 +63,12 @@ class RoomAliasBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomAliasBot override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(RoomAliasBottomSheetSharedActionViewModel::class.java) - recyclerView.configureWith(controller, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) + bottomSheetRecyclerView.configureWith(controller, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() controller.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index d8c8c41936..d66599db91 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -81,8 +81,8 @@ class RoomSettingsFragment @Inject constructor( controller.callback = this setupToolbar(roomSettingsToolbar) roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) - waiting_view_status_text.setText(R.string.please_wait) - waiting_view_status_text.isVisible = true + waitingStatusText.setText(R.string.please_wait) + waitingStatusText.isVisible = true viewModel.observeViewEvents { when (it) { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt index 1d8e95a18e..c458d6a74c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt @@ -22,15 +22,10 @@ import android.content.Intent import android.content.IntentFilter import android.os.Bundle import android.view.View -import android.view.ViewGroup -import android.widget.Button -import android.widget.TextView import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import androidx.transition.TransitionManager -import butterknife.BindView import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.registerStartForActivityResult @@ -41,6 +36,7 @@ import im.vector.app.features.rageshake.BugReporter import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TroubleshootTest import im.vector.app.push.fcm.NotificationTroubleshootTestManagerFactory +import kotlinx.android.synthetic.main.fragment_settings_notifications_troubleshoot.* import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject @@ -50,21 +46,6 @@ class VectorSettingsNotificationsTroubleshootFragment @Inject constructor( private val testManagerFactory: NotificationTroubleshootTestManagerFactory ) : VectorBaseFragment() { - @BindView(R.id.troubleshoot_test_recycler_view) - lateinit var mRecyclerView: RecyclerView - - @BindView(R.id.troubleshoot_bottom_view) - lateinit var mBottomView: ViewGroup - - @BindView(R.id.toubleshoot_summ_description) - lateinit var mSummaryDescription: TextView - - @BindView(R.id.troubleshoot_summ_button) - lateinit var mSummaryButton: Button - - @BindView(R.id.troubleshoot_run_button) - lateinit var mRunButton: Button - private var testManager: NotificationTroubleshootTestManager? = null // members @@ -76,71 +57,71 @@ class VectorSettingsNotificationsTroubleshootFragment @Inject constructor( super.onViewCreated(view, savedInstanceState) val layoutManager = LinearLayoutManager(context) - mRecyclerView.layoutManager = layoutManager + troubleshoot_test_recycler_view.layoutManager = layoutManager - val dividerItemDecoration = DividerItemDecoration(mRecyclerView.context, + val dividerItemDecoration = DividerItemDecoration(troubleshoot_test_recycler_view.context, layoutManager.orientation) - mRecyclerView.addItemDecoration(dividerItemDecoration) + troubleshoot_test_recycler_view.addItemDecoration(dividerItemDecoration) - mSummaryButton.debouncedClicks { + troubleshoot_summ_button.debouncedClicks { bugReporter.openBugReportScreen(requireActivity()) } - mRunButton.debouncedClicks { + troubleshoot_run_button.debouncedClicks { testManager?.retry(testStartForActivityResult) } startUI() } private fun startUI() { - mSummaryDescription.text = getString(R.string.settings_troubleshoot_diagnostic_running_status, 0, 0) + toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_running_status, 0, 0) testManager = testManagerFactory.create(this) testManager?.statusListener = { troubleshootTestManager -> if (isAdded) { - TransitionManager.beginDelayedTransition(mBottomView) + TransitionManager.beginDelayedTransition(troubleshoot_bottom_view) when (troubleshootTestManager.diagStatus) { TroubleshootTest.TestStatus.NOT_STARTED -> { - mSummaryDescription.text = "" - mSummaryButton.visibility = View.GONE - mRunButton.visibility = View.VISIBLE + toubleshoot_summ_description.text = "" + troubleshoot_summ_button.visibility = View.GONE + troubleshoot_run_button.visibility = View.VISIBLE } TroubleshootTest.TestStatus.RUNNING, TroubleshootTest.TestStatus.WAITING_FOR_USER -> { val size = troubleshootTestManager.testListSize val currentTestIndex = troubleshootTestManager.currentTestIndex - mSummaryDescription.text = getString( + toubleshoot_summ_description.text = getString( R.string.settings_troubleshoot_diagnostic_running_status, currentTestIndex, size ) - mSummaryButton.visibility = View.GONE - mRunButton.visibility = View.GONE + troubleshoot_summ_button.visibility = View.GONE + troubleshoot_run_button.visibility = View.GONE } TroubleshootTest.TestStatus.FAILED -> { // check if there are quick fixes val hasQuickFix = testManager?.hasQuickFix().orFalse() if (hasQuickFix) { - mSummaryDescription.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_with_quickfix) + toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_with_quickfix) } else { - mSummaryDescription.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_no_quickfix) + toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_no_quickfix) } - mSummaryButton.visibility = View.VISIBLE - mRunButton.visibility = View.VISIBLE + troubleshoot_summ_button.visibility = View.VISIBLE + troubleshoot_run_button.visibility = View.VISIBLE } TroubleshootTest.TestStatus.SUCCESS -> { - mSummaryDescription.text = getString(R.string.settings_troubleshoot_diagnostic_success_status) - mSummaryButton.visibility = View.VISIBLE - mRunButton.visibility = View.VISIBLE + toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_success_status) + troubleshoot_summ_button.visibility = View.VISIBLE + troubleshoot_run_button.visibility = View.VISIBLE } } } } - mRecyclerView.adapter = testManager?.adapter + troubleshoot_test_recycler_view.adapter = testManager?.adapter testManager?.runDiagnostic(testStartForActivityResult) } override fun onDestroyView() { - mRecyclerView.cleanup() + troubleshoot_test_recycler_view.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt index dbaa99e1df..7cc25170cb 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt @@ -19,8 +19,6 @@ import android.os.Bundle import android.os.Parcelable import android.view.View import androidx.core.view.isVisible -import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.parentFragmentViewModel @@ -48,9 +46,6 @@ class DeviceVerificationInfoBottomSheet : VectorBaseBottomSheetDialogFragment(), @Inject lateinit var deviceVerificationInfoViewModelFactory: DeviceVerificationInfoBottomSheetViewModel.Factory - @BindView(R.id.bottomSheetRecyclerView) - lateinit var recyclerView: RecyclerView - override fun injectWith(injector: ScreenComponent) { injector.inject(this) } @@ -61,7 +56,7 @@ class DeviceVerificationInfoBottomSheet : VectorBaseBottomSheetDialogFragment(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - recyclerView.configureWith( + bottomSheetRecyclerView.configureWith( controller, showDivider = false, hasFixedSize = false) @@ -70,7 +65,7 @@ class DeviceVerificationInfoBottomSheet : VectorBaseBottomSheetDialogFragment(), } override fun onDestroyView() { - recyclerView.cleanup() + bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt index a317536d5d..520a63d1a9 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt @@ -58,8 +58,8 @@ class VectorSettingsDevicesFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - waiting_view_status_text.setText(R.string.please_wait) - waiting_view_status_text.isVisible = true + waitingStatusText.setText(R.string.please_wait) + waitingStatusText.isVisible = true devicesController.callback = this genericRecyclerView.configureWith(devicesController, showDivider = true) viewModel.observeViewEvents { diff --git a/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt b/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt index 5ad7258cec..8bca7243a6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt @@ -46,8 +46,8 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - waiting_view_status_text.setText(R.string.please_wait) - waiting_view_status_text.isVisible = true + waitingStatusText.setText(R.string.please_wait) + waitingStatusText.isVisible = true ignoredUsersController.callback = this genericRecyclerView.configureWith(ignoredUsersController) viewModel.observeViewEvents { diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt index 5b96bcb254..321a2b3e94 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt @@ -18,16 +18,11 @@ package im.vector.app.features.settings.troubleshoot import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.TextView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R import im.vector.app.features.themes.ThemeUtils +import kotlinx.android.synthetic.main.item_notification_troubleshoot.view.* class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList) : RecyclerView.Adapter() { @@ -49,86 +44,67 @@ class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList { - titleText.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary)) + itemView.troubleshootTestTitle.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary)) - progressBar.visibility = View.INVISIBLE - statusIconImage.visibility = View.VISIBLE - statusIconImage.setImageResource(R.drawable.unit_test) + itemView.troubleshootProgressBar.visibility = View.INVISIBLE + itemView.troubleshootStatusIcon.visibility = View.VISIBLE + itemView.troubleshootStatusIcon.setImageResource(R.drawable.unit_test) } TroubleshootTest.TestStatus.WAITING_FOR_USER -> { - progressBar.visibility = View.INVISIBLE - statusIconImage.visibility = View.VISIBLE + itemView.troubleshootProgressBar.visibility = View.INVISIBLE + itemView.troubleshootStatusIcon.visibility = View.VISIBLE val infoColor = ContextCompat.getColor(context, R.color.vector_info_color) val drawable = ContextCompat.getDrawable(itemView.context, R.drawable.ic_notification_privacy_warning)?.apply { ThemeUtils.tintDrawableWithColor(this, infoColor) } - statusIconImage.setImageDrawable(drawable) - descriptionText.setTextColor(infoColor) + itemView.troubleshootStatusIcon.setImageDrawable(drawable) + itemView.troubleshootTestDescription.setTextColor(infoColor) } TroubleshootTest.TestStatus.RUNNING -> { - progressBar.visibility = View.VISIBLE - statusIconImage.visibility = View.INVISIBLE + itemView.troubleshootProgressBar.visibility = View.VISIBLE + itemView.troubleshootStatusIcon.visibility = View.INVISIBLE } TroubleshootTest.TestStatus.FAILED -> { - progressBar.visibility = View.INVISIBLE - statusIconImage.visibility = View.VISIBLE - statusIconImage.setImageResource(R.drawable.unit_test_ko) + itemView.troubleshootProgressBar.visibility = View.INVISIBLE + itemView.troubleshootStatusIcon.visibility = View.VISIBLE + itemView.troubleshootStatusIcon.setImageResource(R.drawable.unit_test_ko) - statusIconImage.imageTintList = null + itemView.troubleshootStatusIcon.imageTintList = null - descriptionText.setTextColor(ContextCompat.getColor(context, R.color.riotx_notice)) + itemView.troubleshootTestDescription.setTextColor(ContextCompat.getColor(context, R.color.riotx_notice)) } TroubleshootTest.TestStatus.SUCCESS -> { - progressBar.visibility = View.INVISIBLE - statusIconImage.visibility = View.VISIBLE - statusIconImage.setImageResource(R.drawable.unit_test_ok) + itemView.troubleshootProgressBar.visibility = View.INVISIBLE + itemView.troubleshootStatusIcon.visibility = View.VISIBLE + itemView.troubleshootStatusIcon.setImageResource(R.drawable.unit_test_ok) } } val quickFix = test.quickFix if (quickFix != null) { - fixButton.setText(test.quickFix!!.title) - fixButton.setOnClickListener { _ -> + itemView.troubleshootTestButton.setText(test.quickFix!!.title) + itemView.troubleshootTestButton.setOnClickListener { _ -> test.quickFix!!.doFix() } - fixButton.visibility = View.VISIBLE + itemView.troubleshootTestButton.visibility = View.VISIBLE } else { - fixButton.visibility = View.GONE + itemView.troubleshootTestButton.visibility = View.GONE } - titleText.setText(test.titleResId) + itemView.troubleshootTestTitle.setText(test.titleResId) val description = test.description if (description == null) { - descriptionText.visibility = View.GONE + itemView.troubleshootTestDescription.visibility = View.GONE } else { - descriptionText.visibility = View.VISIBLE - descriptionText.text = description + itemView.troubleshootTestDescription.visibility = View.VISIBLE + itemView.troubleshootTestDescription.text = description } } } diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt index 3b73455923..8b014eb6a2 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt @@ -20,65 +20,51 @@ import android.content.Context import android.content.res.ColorStateList import android.graphics.drawable.Drawable import android.util.AttributeSet -import android.view.View -import android.widget.ImageView import android.widget.LinearLayout -import android.widget.TextView import androidx.core.view.isVisible -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.features.themes.ThemeUtils +import kotlinx.android.synthetic.main.item_signout_action.view.* class SignOutBottomSheetActionButton @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { - @BindView(R.id.actionTitleText) - lateinit var actionTextView: TextView - - @BindView(R.id.actionIconImageView) - lateinit var iconImageView: ImageView - - @BindView(R.id.signedOutActionClickable) - lateinit var clickableZone: View - var action: (() -> Unit)? = null var title: String? = null set(value) { field = value - actionTextView.setTextOrHide(value) + actionTitleText.setTextOrHide(value) } var leftIcon: Drawable? = null set(value) { field = value if (value == null) { - iconImageView.isVisible = false - iconImageView.setImageDrawable(null) + actionIconImageView.isVisible = false + actionIconImageView.setImageDrawable(null) } else { - iconImageView.isVisible = true - iconImageView.setImageDrawable(value) + actionIconImageView.isVisible = true + actionIconImageView.setImageDrawable(value) } } var tint: Int? = null set(value) { field = value - iconImageView.imageTintList = value?.let { ColorStateList.valueOf(value) } + actionIconImageView.imageTintList = value?.let { ColorStateList.valueOf(value) } } var textColor: Int? = null set(value) { field = value - textColor?.let { actionTextView.setTextColor(it) } + textColor?.let { actionTitleText.setTextColor(it) } } init { inflate(context, R.layout.item_signout_action, this) - ButterKnife.bind(this) val typedArray = context.obtainStyledAttributes(attrs, R.styleable.SignOutBottomSheetActionButton, 0, 0) title = typedArray.getString(R.styleable.SignOutBottomSheetActionButton_actionTitle) ?: "" @@ -88,7 +74,7 @@ class SignOutBottomSheetActionButton @JvmOverloads constructor( typedArray.recycle() - clickableZone.setOnClickListener { + signedOutActionClickable.setOnClickListener { action?.invoke() } } diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt index 830e9beabc..49c688c801 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt @@ -20,14 +20,9 @@ import android.app.Activity import android.app.Dialog import android.os.Bundle import android.view.View -import android.view.ViewGroup import android.widget.FrameLayout -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible -import butterknife.BindView import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success import com.airbnb.mvrx.fragmentViewModel @@ -52,27 +47,6 @@ import javax.inject.Inject // TODO this needs to be refactored to current standard and remove legacy class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), SignoutCheckViewModel.Factory { - @BindView(R.id.bottom_sheet_signout_warning_text) - lateinit var sheetTitle: TextView - - @BindView(R.id.bottom_sheet_signout_backingup_status_group) - lateinit var backingUpStatusGroup: ViewGroup - - @BindView(R.id.bottom_sheet_signout_icon_progress_bar) - lateinit var backupProgress: ProgressBar - - @BindView(R.id.bottom_sheet_signout_icon) - lateinit var backupCompleteImage: ImageView - - @BindView(R.id.bottom_sheet_backup_status_text) - lateinit var backupStatusTex: TextView - - @BindView(R.id.signoutExportingLoading) - lateinit var signoutExportingLoading: View - - @BindView(R.id.root_layout) - lateinit var rootLayout: ViewGroup - var onSignOut: Runnable? = null companion object { @@ -164,7 +138,7 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), override fun invalidate() = withState(viewModel) { state -> signoutExportingLoading.isVisible = false if (state.crossSigningSetupAllKeysKnown && !state.backupIsSetup) { - sheetTitle.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) + bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) backingUpStatusGroup.isVisible = false // we should show option to setup 4S setupRecoveryButton.isVisible = true @@ -174,7 +148,7 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), exitAnywayButton.isVisible = true signOutButton.isVisible = false } else if (state.keysBackupState == KeysBackupState.Unknown || state.keysBackupState == KeysBackupState.Disabled) { - sheetTitle.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) + bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) backingUpStatusGroup.isVisible = false // no key backup and cannot setup full 4S // we propose to setup @@ -192,13 +166,13 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), when (state.keysBackupState) { KeysBackupState.ReadyToBackUp -> { - sheetTitle.text = getString(R.string.action_sign_out_confirmation_simple) + bottom_sheet_signout_warning_text.text = getString(R.string.action_sign_out_confirmation_simple) // Ok all keys are backedUp backingUpStatusGroup.isVisible = true backupProgress.isVisible = false backupCompleteImage.isVisible = true - backupStatusTex.text = getString(R.string.keys_backup_info_keys_all_backup_up) + backupStatusText.text = getString(R.string.keys_backup_info_keys_all_backup_up) setupMegolmBackupButton.isVisible = false exportManuallyButton.isVisible = false @@ -208,13 +182,13 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), } KeysBackupState.WillBackUp, KeysBackupState.BackingUp -> { - sheetTitle.text = getString(R.string.sign_out_bottom_sheet_warning_backing_up) + bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_backing_up) // save in progress backingUpStatusGroup.isVisible = true backupProgress.isVisible = true backupCompleteImage.isVisible = false - backupStatusTex.text = getString(R.string.sign_out_bottom_sheet_backing_up_keys) + backupStatusText.text = getString(R.string.sign_out_bottom_sheet_backing_up_keys) setupMegolmBackupButton.isVisible = false exportManuallyButton.isVisible = false @@ -222,7 +196,7 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), signOutButton.isVisible = false } KeysBackupState.NotTrusted -> { - sheetTitle.text = getString(R.string.sign_out_bottom_sheet_warning_backup_not_active) + bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_backup_not_active) // It's not trusted and we know there are unsaved keys.. backingUpStatusGroup.isVisible = false @@ -254,7 +228,7 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), } is Success -> { if (state.hasBeenExportedToFile.invoke()) { - sheetTitle.text = getString(R.string.action_sign_out_confirmation_simple) + bottom_sheet_signout_warning_text.text = getString(R.string.action_sign_out_confirmation_simple) backingUpStatusGroup.isVisible = false setupRecoveryButton.isVisible = false diff --git a/vector/src/main/res/layout/activity.xml b/vector/src/main/res/layout/activity.xml index 9e56d9e605..e5f6655263 100644 --- a/vector/src/main/res/layout/activity.xml +++ b/vector/src/main/res/layout/activity.xml @@ -1,7 +1,7 @@ diff --git a/vector/src/main/res/layout/activity_call.xml b/vector/src/main/res/layout/activity_call.xml index b2af9f8a9d..d2d39de67f 100644 --- a/vector/src/main/res/layout/activity_call.xml +++ b/vector/src/main/res/layout/activity_call.xml @@ -10,14 +10,14 @@ tools:ignore="MergeRootFrame"> diff --git a/vector/src/main/res/layout/activity_home.xml b/vector/src/main/res/layout/activity_home.xml index 61fb1b5ad4..f8496f4116 100644 --- a/vector/src/main/res/layout/activity_home.xml +++ b/vector/src/main/res/layout/activity_home.xml @@ -7,7 +7,7 @@ tools:openDrawer="start"> diff --git a/vector/src/main/res/layout/activity_room_detail.xml b/vector/src/main/res/layout/activity_room_detail.xml index cc10341d2f..4139aa12dc 100644 --- a/vector/src/main/res/layout/activity_room_detail.xml +++ b/vector/src/main/res/layout/activity_room_detail.xml @@ -7,7 +7,7 @@ tools:openDrawer="start"> diff --git a/vector/src/main/res/layout/activity_simple.xml b/vector/src/main/res/layout/activity_simple.xml index d7382d173d..346f451f44 100644 --- a/vector/src/main/res/layout/activity_simple.xml +++ b/vector/src/main/res/layout/activity_simple.xml @@ -1,7 +1,7 @@ diff --git a/vector/src/main/res/layout/activity_vector_settings.xml b/vector/src/main/res/layout/activity_vector_settings.xml index 395acd37a4..e204514bff 100755 --- a/vector/src/main/res/layout/activity_vector_settings.xml +++ b/vector/src/main/res/layout/activity_vector_settings.xml @@ -1,6 +1,6 @@ diff --git a/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml b/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml index 63a250e219..b867a129a4 100644 --- a/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml +++ b/vector/src/main/res/layout/bottom_sheet_logout_and_backup.xml @@ -2,7 +2,7 @@ + app:layout_constraintTop_toBottomOf="@+id/otherUserAvatarImageView" /> diff --git a/vector/src/main/res/layout/composer_layout.xml b/vector/src/main/res/layout/composer_layout.xml index cb0b37d844..5dd24676c1 100644 --- a/vector/src/main/res/layout/composer_layout.xml +++ b/vector/src/main/res/layout/composer_layout.xml @@ -33,14 +33,14 @@ tools:ignore="MissingConstraints" /> @@ -96,7 +96,7 @@ tools:ignore="MissingConstraints" /> @@ -113,13 +113,13 @@ android:background="?android:attr/selectableItemBackground" android:src="@drawable/ic_attachment" app:layout_constraintBottom_toBottomOf="@id/sendButton" - app:layout_constraintEnd_toStartOf="@+id/composer_shield" + app:layout_constraintEnd_toStartOf="@+id/composerShieldImageView" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/sendButton" tools:ignore="MissingPrefix" /> \ No newline at end of file diff --git a/vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml b/vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml index 8a76c0547e..49f45ab654 100644 --- a/vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml +++ b/vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml @@ -36,67 +36,67 @@ app:layout_constraintStart_toStartOf="@+id/related_message_background" /> @@ -106,7 +106,7 @@ android:layout_height="0dp" app:barrierDirection="bottom" app:barrierMargin="8dp" - app:constraint_referenced_ids="composer_related_message_preview,composer_related_message_action_image" + app:constraint_referenced_ids="composerRelatedMessageContent,composerRelatedMessageActionIcon" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> @@ -123,7 +123,7 @@ tools:ignore="MissingPrefix" /> @@ -85,7 +85,7 @@ android:textColor="?riotx_text_secondary" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/keys_backup_key_enter_til" /> + app:layout_constraintTop_toBottomOf="@+id/mKeyInputLayout" /> + app:layout_constraintTop_toBottomOf="@+id/helperTextWithLink" /> \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_keys_backup_restore_success.xml b/vector/src/main/res/layout/fragment_keys_backup_restore_success.xml index f5ce626c8f..d9a426448c 100644 --- a/vector/src/main/res/layout/fragment_keys_backup_restore_success.xml +++ b/vector/src/main/res/layout/fragment_keys_backup_restore_success.xml @@ -19,7 +19,7 @@ tools:ignore="MissingPrefix" /> + app:layout_constraintTop_toBottomOf="@+id/mSuccessDetailsText" /> diff --git a/vector/src/main/res/layout/fragment_keys_backup_setup_step1.xml b/vector/src/main/res/layout/fragment_keys_backup_setup_step1.xml index 29d2137ddd..2345349de8 100644 --- a/vector/src/main/res/layout/fragment_keys_backup_setup_step1.xml +++ b/vector/src/main/res/layout/fragment_keys_backup_setup_step1.xml @@ -63,7 +63,7 @@ app:layout_constraintTop_toBottomOf="@id/keys_backup_setup_step1_description" /> diff --git a/vector/src/main/res/layout/fragment_keys_backup_setup_step2.xml b/vector/src/main/res/layout/fragment_keys_backup_setup_step2.xml index 6615b845df..16c810fd63 100644 --- a/vector/src/main/res/layout/fragment_keys_backup_setup_step2.xml +++ b/vector/src/main/res/layout/fragment_keys_backup_setup_step2.xml @@ -83,7 +83,7 @@ tools:ignore="MissingPrefix" /> + app:layout_constraintTop_toBottomOf="@id/mPassphraseProgressLevel"> + app:layout_constraintTop_toBottomOf="@id/mPassphraseConfirmInputLayout" /> diff --git a/vector/src/main/res/layout/merge_overlay_waiting_view.xml b/vector/src/main/res/layout/merge_overlay_waiting_view.xml index c13d5e5df2..0efed2dad9 100644 --- a/vector/src/main/res/layout/merge_overlay_waiting_view.xml +++ b/vector/src/main/res/layout/merge_overlay_waiting_view.xml @@ -35,14 +35,14 @@ android:orientation="horizontal"> @@ -73,7 +73,7 @@ app:tint="?attr/riotx_text_primary" /> From 838340bbc84f37a09ae799af2dccd02b73910572 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 15 Dec 2020 20:33:55 +0100 Subject: [PATCH 003/224] Remove dependency to Butterknife --- tools/check/forbidden_strings_in_code.txt | 3 --- vector/build.gradle | 4 ---- vector/src/main/assets/open_source_licenses.html | 5 ----- 3 files changed, 12 deletions(-) diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index fc510e585c..f19b9719a8 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -109,9 +109,6 @@ import retrofit2\.adapter\.rxjava\.HttpException ### This is generally not necessary, no need to reset the padding if there is no drawable setCompoundDrawablePadding\(0\) -### Deprecated use class form SDK API 26 -ButterKnife\.findById\( - # Change thread with Rx # DISABLED #runOnUiThread diff --git a/vector/build.gradle b/vector/build.gradle index 70d38b1c2a..f526e31b60 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -386,10 +386,6 @@ dependencies { implementation 'com.otaliastudios:autocomplete:1.1.0' - // Butterknife - implementation 'com.jakewharton:butterknife:10.2.0' - kapt 'com.jakewharton:butterknife-compiler:10.2.0' - // Shake detection implementation 'com.squareup:seismic:1.0.2' diff --git a/vector/src/main/assets/open_source_licenses.html b/vector/src/main/assets/open_source_licenses.html index bf341e38b7..17d79e3655 100755 --- a/vector/src/main/assets/open_source_licenses.html +++ b/vector/src/main/assets/open_source_licenses.html @@ -312,11 +312,6 @@ SOFTWARE.
Copyright (c) 2017 -
  • - Butterknife -
    - Copyright 2013 Jake Wharton -
  • seismic
    From 706736273c6b80ecf5f32b8ed5d8295bbaede2a2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Dec 2020 00:46:52 +0100 Subject: [PATCH 004/224] Migrate to ViewBindings (#1072) - WIP --- CHANGES.md | 2 +- attachment-viewer/build.gradle | 5 +- .../AttachmentViewerActivity.kt | 52 +++---- matrix-sdk-android/build.gradle | 6 +- .../sdk/api/auth/data/SsoIdentityProvider.kt | 2 +- .../session/content/ContentAttachmentData.kt | 2 +- .../LocalizedFlowDataLoginTerms.kt | 2 +- .../crypto/attachments/ElementToDecrypt.kt | 2 +- multipicker/build.gradle | 2 +- .../root/src/app_package/Fragment.kt.ftl | 2 +- vector/build.gradle | 10 +- .../debug/DebugMaterialThemeActivity.kt | 2 +- .../app/features/debug/DebugMenuActivity.kt | 24 ++-- .../app/features/debug/TestLinkifyActivity.kt | 2 +- .../debug/sas/DebugSasEmojiActivity.kt | 6 +- .../core/dialogs/ConfirmationDialogBuilder.kt | 2 +- .../im/vector/app/core/extensions/Activity.kt | 24 ++-- .../im/vector/app/core/extensions/Fragment.kt | 25 ++-- .../app/core/platform/ButtonStateView.kt | 2 +- .../core/platform/SimpleFragmentActivity.kt | 45 +++--- .../im/vector/app/core/platform/StateView.kt | 2 +- .../app/core/platform/VectorBaseActivity.kt | 31 ++-- .../VectorBaseBottomSheetDialogFragment.kt | 19 ++- .../app/core/platform/VectorBaseFragment.kt | 29 ++-- .../core/ui/bottomsheet/BottomSheetGeneric.kt | 16 ++- .../core/ui/views/BottomSheetActionButton.kt | 28 ++-- .../app/core/ui/views/JumpToReadMarkerView.kt | 2 +- .../app/core/ui/views/KeysBackupBanner.kt | 2 +- .../app/core/ui/views/NotificationAreaView.kt | 2 +- .../app/core/ui/views/PasswordStrengthBar.kt | 2 +- .../app/core/ui/views/ReadReceiptsView.kt | 2 +- .../im/vector/app/features/MainActivity.kt | 8 +- .../preview/AttachmentsPreviewActivity.kt | 6 +- .../preview/AttachmentsPreviewFragment.kt | 36 ++--- .../features/call/CallControlsBottomSheet.kt | 42 +++--- .../app/features/call/CallControlsView.kt | 41 ++++-- .../app/features/call/VectorCallActivity.kt | 97 +++++++------ .../call/conference/VectorJitsiActivity.kt | 12 +- .../contactsbook/ContactsBookFragment.kt | 29 ++-- .../createdirect/CreateDirectRoomActivity.kt | 2 +- .../CreateDirectRoomByQrCodeFragment.kt | 20 ++- .../KeysBackupRestoreFromKeyFragment.kt | 30 ++-- ...KeysBackupRestoreFromPassphraseFragment.kt | 30 ++-- .../KeysBackupRestoreSuccessFragment.kt | 22 +-- .../settings/KeysBackupSettingsFragment.kt | 16 ++- .../setup/KeysBackupSetupStep1Fragment.kt | 20 ++- .../setup/KeysBackupSetupStep2Fragment.kt | 12 +- .../setup/KeysBackupSetupStep3Fragment.kt | 12 +- .../quads/SharedSecureStorageActivity.kt | 4 +- .../quads/SharedSecuredStorageKeyFragment.kt | 12 +- .../SharedSecuredStoragePassphraseFragment.kt | 40 +++--- .../SharedSecuredStorageResetAllFragment.kt | 21 ++- .../BootstrapAccountPasswordFragment.kt | 16 ++- .../crypto/recover/BootstrapBottomSheet.kt | 62 ++++---- .../recover/BootstrapConclusionFragment.kt | 16 ++- .../BootstrapConfirmPassphraseFragment.kt | 13 +- .../BootstrapEnterPassphraseFragment.kt | 45 +++--- .../recover/BootstrapMigrateBackupFragment.kt | 14 +- .../BootstrapSaveRecoveryKeyFragment.kt | 22 +-- .../BootstrapSetupRecoveryKeyFragment.kt | 43 +++--- .../recover/BootstrapWaitingFragment.kt | 23 +-- .../verification/QuadSLoadingFragment.kt | 10 +- .../verification/VerificationBottomSheet.kt | 42 +++--- .../cancel/VerificationCancelFragment.kt | 17 ++- .../cancel/VerificationNotMeFragment.kt | 17 ++- .../VerificationChooseMethodFragment.kt | 16 ++- .../VerificationConclusionFragment.kt | 18 ++- .../emoji/VerificationEmojiCodeFragment.kt | 16 ++- .../VerificationQRWaitingFragment.kt | 17 ++- .../VerificationQrScannedByOtherFragment.kt | 16 ++- .../request/VerificationRequestFragment.kt | 16 ++- .../discovery/DiscoverySettingsFragment.kt | 20 ++- .../change/SetIdentityServerFragment.kt | 14 +- .../features/grouplist/GroupListFragment.kt | 23 +-- .../vector/app/features/home/HomeActivity.kt | 49 ++++--- .../app/features/home/HomeDetailFragment.kt | 61 ++++---- .../app/features/home/HomeDrawerFragment.kt | 36 +++-- .../app/features/home/LoadingFragment.kt | 14 +- .../room/breadcrumbs/BreadcrumbsFragment.kt | 19 ++- .../home/room/detail/RoomDetailActivity.kt | 4 +- .../home/room/detail/RoomDetailFragment.kt | 8 +- .../room/detail/composer/TextComposerView.kt | 2 +- .../DisplayReadReceiptsBottomSheet.kt | 22 ++- .../home/room/detail/search/SearchActivity.kt | 13 +- .../home/room/detail/search/SearchFragment.kt | 36 +++-- .../action/MessageActionsBottomSheet.kt | 21 ++- .../action/TimelineEventFragmentArgs.kt | 2 +- .../edithistory/ViewEditHistoryBottomSheet.kt | 19 ++- .../timeline/item/MessageInformationData.kt | 2 +- .../timeline/item/PollResultLineView.kt | 2 +- .../reactions/ViewReactionsBottomSheet.kt | 20 ++- .../detail/timeline/url/PreviewUrlView.kt | 2 +- .../detail/widget/RoomWidgetsBannerView.kt | 2 +- .../detail/widget/RoomWidgetsBottomSheet.kt | 24 ++-- .../room/filtered/FilteredRoomsActivity.kt | 14 +- .../home/room/list/RoomListFragment.kt | 17 ++- .../RoomListQuickActionsBottomSheet.kt | 19 ++- .../room/list/widget/NotifsFabMenuView.kt | 2 +- .../invite/InviteUsersToRoomActivity.kt | 4 +- .../app/features/invite/VectorInviteView.kt | 18 ++- .../app/features/link/LinkHandlerActivity.kt | 6 +- .../features/login/AbstractLoginFragment.kt | 3 +- .../login/AbstractSSOLoginFragment.kt | 3 +- .../app/features/login/LoginActivity.kt | 10 +- .../features/login/LoginCaptchaFragment.kt | 26 ++-- .../vector/app/features/login/LoginConfig.kt | 2 +- .../app/features/login/LoginFragment.kt | 132 +++++++++-------- .../LoginGenericTextInputFormFragment.kt | 14 +- .../im/vector/app/features/login/LoginMode.kt | 2 +- .../login/LoginResetPasswordFragment.kt | 12 +- ...inResetPasswordMailConfirmationFragment.kt | 16 ++- .../LoginResetPasswordSuccessFragment.kt | 15 +- .../login/LoginServerSelectionFragment.kt | 26 ++-- .../login/LoginServerUrlFormFragment.kt | 12 +- .../LoginSignUpSignInSelectionFragment.kt | 12 +- .../app/features/login/LoginSplashFragment.kt | 14 +- .../login/LoginWaitForEmailFragment.kt | 16 ++- .../app/features/login/LoginWebFragment.kt | 36 +++-- .../login/terms/LoginTermsFragment.kt | 22 +-- .../features/matrixto/MatrixToBottomSheet.kt | 51 ++++--- .../features/media/BigImageViewerActivity.kt | 13 +- .../features/media/ImageContentRenderer.kt | 2 +- .../media/VectorAttachmentViewerActivity.kt | 2 +- .../features/media/VideoContentRenderer.kt | 2 +- .../permalink/PermalinkHandlerActivity.kt | 5 +- .../im/vector/app/features/pin/PinActivity.kt | 5 +- .../im/vector/app/features/pin/PinFragment.kt | 12 +- .../features/qrcode/QrCodeScannerActivity.kt | 5 +- .../features/qrcode/QrCodeScannerFragment.kt | 18 ++- .../features/rageshake/BugReportActivity.kt | 86 +++++------ .../reactions/EmojiChooserFragment.kt | 16 ++- .../reactions/EmojiReactionPickerActivity.kt | 21 +-- .../reactions/EmojiSearchResultFragment.kt | 15 +- .../roomdirectory/PublicRoomsFragment.kt | 31 ++-- .../roomdirectory/RoomDirectoryActivity.kt | 5 +- .../createroom/CreateRoomActivity.kt | 5 +- .../createroom/CreateRoomFragment.kt | 30 ++-- .../picker/RoomDirectoryPickerFragment.kt | 22 ++- .../roompreview/RoomPreviewActivity.kt | 7 +- .../RoomPreviewNoPreviewFragment.kt | 12 +- .../RoomMemberProfileFragment.kt | 17 ++- .../devices/DeviceListBottomSheet.kt | 13 +- .../devices/DeviceListFragment.kt | 19 ++- .../devices/DeviceTrustInfoActionFragment.kt | 19 ++- .../powerlevel/EditPowerLevelDialogs.kt | 2 +- .../roomprofile/RoomProfileFragment.kt | 18 ++- .../roomprofile/alias/RoomAliasFragment.kt | 30 ++-- .../alias/detail/RoomAliasBottomSheet.kt | 19 ++- .../banned/RoomBannedMemberListFragment.kt | 28 ++-- .../members/RoomMemberListFragment.kt | 21 ++- .../settings/RoomSettingsFragment.kt | 29 ++-- .../RoomHistoryVisibilityBottomSheet.kt | 2 +- .../joinrule/RoomJoinRuleBottomSheet.kt | 2 +- .../uploads/RoomUploadsFragment.kt | 27 ++-- .../uploads/files/RoomUploadsFilesFragment.kt | 30 ++-- .../uploads/media/RoomUploadsMediaFragment.kt | 37 ++--- .../settings/VectorSettingsActivity.kt | 9 +- .../settings/VectorSettingsBaseFragment.kt | 4 +- ...ttingsNotificationsTroubleshootFragment.kt | 14 +- .../deactivation/DeactivateAccountFragment.kt | 14 +- .../CrossSigningSettingsFragment.kt | 20 ++- .../DeviceVerificationInfoBottomSheet.kt | 22 ++- .../devices/VectorSettingsDevicesFragment.kt | 32 +++-- .../settings/devtools/AccountDataFragment.kt | 19 ++- .../GossipingEventsPaperTrailFragment.kt | 16 ++- .../IncomingKeyRequestListFragment.kt | 15 +- .../settings/devtools/KeyRequestsFragment.kt | 27 ++-- .../OutgoingKeyRequestListFragment.kt | 16 ++- .../VectorSettingsIgnoredUsersFragment.kt | 30 ++-- .../settings/locale/LocalePickerFragment.kt | 21 ++- .../settings/push/PushGatewaysFragment.kt | 18 ++- .../settings/push/PushRulesFragment.kt | 18 ++- .../threepids/ThreePidsSettingsFragment.kt | 18 ++- ...ficationTroubleshootRecyclerViewAdapter.kt | 2 +- .../features/share/IncomingShareActivity.kt | 5 +- .../features/share/IncomingShareFragment.kt | 27 ++-- .../vector/app/features/share/SharedData.kt | 2 +- .../signout/hard/SignedOutActivity.kt | 10 +- .../signout/soft/SoftLogoutActivity.kt | 2 +- .../signout/soft/SoftLogoutFragment.kt | 18 ++- .../app/features/sync/widget/SyncStateView.kt | 2 +- .../app/features/terms/ReviewTermsFragment.kt | 15 +- .../app/features/terms/ServiceTermsArgs.kt | 2 +- .../features/usercode/ScanUserCodeFragment.kt | 12 +- .../features/usercode/ShowUserCodeFragment.kt | 26 ++-- .../app/features/usercode/UserCodeActivity.kt | 16 ++- .../userdirectory/UserListFragment.kt | 45 +++--- .../userdirectory/UserListFragmentArgs.kt | 2 +- .../webview/ConsentWebViewEventListener.kt | 4 +- .../features/webview/VectorWebViewActivity.kt | 24 ++-- .../webview/WebViewEventListenerFactory.kt | 2 +- .../app/features/webview/WebViewMode.kt | 4 +- .../app/features/widgets/WidgetActivity.kt | 15 +- .../app/features/widgets/WidgetFragment.kt | 17 ++- .../RoomWidgetPermissionBottomSheet.kt | 25 ++-- .../signout/SignOutBottomSheetActionButton.kt | 2 +- .../SignOutBottomSheetDialogFragment.kt | 134 ++++++++++-------- vector/src/main/res/layout/activity.xml | 4 +- vector/src/main/res/layout/activity_home.xml | 4 +- .../main/res/layout/activity_room_detail.xml | 4 +- .../main/res/layout/fragment_create_room.xml | 4 +- .../res/layout/fragment_generic_recycler.xml | 4 +- .../res/layout/fragment_matrix_profile.xml | 4 +- .../layout/fragment_room_setting_generic.xml | 4 +- 204 files changed, 2225 insertions(+), 1380 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a2029b9901..e629dd35f2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,7 +23,7 @@ Test: - Other changes: - - + - Migrate to ViewBindings (#1072) Changes in Element 1.0.12 (2020-12-15) =================================================== diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle index 59ba6c4500..d8cd7d0c98 100644 --- a/attachment-viewer/build.gradle +++ b/attachment-viewer/build.gradle @@ -16,7 +16,6 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' buildscript { repositories { @@ -55,6 +54,10 @@ android { kotlinOptions { jvmTarget = '1.8' } + + buildFeatures { + viewBinding true + } } dependencies { diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index 71ce436cf2..ea325a2674 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -33,7 +33,8 @@ import androidx.core.view.isVisible import androidx.core.view.updatePadding import androidx.transition.TransitionManager import androidx.viewpager2.widget.ViewPager2 -import kotlinx.android.synthetic.main.activity_attachment_viewer.* +import im.vector.lib.attachmentviewer.databinding.ActivityAttachmentViewerBinding + import java.lang.ref.WeakReference import kotlin.math.abs @@ -50,12 +51,14 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private var overlayView: View? = null set(value) { if (value == overlayView) return - overlayView?.let { rootContainer.removeView(it) } - rootContainer.addView(value) + overlayView?.let { views.rootContainer.removeView(it) } + views.rootContainer.addView(value) value?.updatePadding(top = topInset, bottom = bottomInset) field = value } + private lateinit var views: ActivityAttachmentViewerBinding + private lateinit var swipeDismissHandler: SwipeToDismissHandler private lateinit var directionDetector: SwipeDirectionDetector private lateinit var scaleDetector: ScaleGestureDetector @@ -95,17 +98,18 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) - setContentView(R.layout.activity_attachment_viewer) - attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL + views = ActivityAttachmentViewerBinding.inflate(layoutInflater) + setContentView(views.root) + views.attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL attachmentsAdapter = AttachmentsAdapter() - attachmentPager.adapter = attachmentsAdapter - imageTransitionView = transitionImageView + views.attachmentPager.adapter = attachmentsAdapter + imageTransitionView = views.transitionImageView transitionImageContainer = findViewById(R.id.transitionImageContainer) - pager2 = attachmentPager + pager2 = views.attachmentPager directionDetector = createSwipeDirectionDetector() gestureDetector = createGestureDetector() - attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + views.attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageScrollStateChanged(state: Int) { isImagePagerIdle = state == ViewPager2.SCROLL_STATE_IDLE } @@ -116,12 +120,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi }) swipeDismissHandler = createSwipeToDismissHandler() - rootContainer.setOnTouchListener(swipeDismissHandler) - rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = dismissContainer.height / 4 } + views.rootContainer.setOnTouchListener(swipeDismissHandler) + views.rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = views.dismissContainer.height / 4 } scaleDetector = createScaleGestureDetector() - ViewCompat.setOnApplyWindowInsetsListener(rootContainer) { _, insets -> + ViewCompat.setOnApplyWindowInsetsListener(views.rootContainer) { _, insets -> overlayView?.updatePadding(top = insets.systemWindowInsetTop, bottom = insets.systemWindowInsetBottom) topInset = insets.systemWindowInsetTop bottomInset = insets.systemWindowInsetBottom @@ -170,7 +174,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi if (swipeDirection == null && (scaleDetector.isInProgress || ev.pointerCount > 1 || wasScaled)) { wasScaled = true // Log.v("ATTACHEMENTS", "dispatch to pager") - return attachmentPager.dispatchTouchEvent(ev) + return views.attachmentPager.dispatchTouchEvent(ev) } // Log.v("ATTACHEMENTS", "is current item scaled ${isScaled()}") @@ -196,16 +200,16 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun handleEventActionDown(event: MotionEvent) { swipeDirection = null wasScaled = false - attachmentPager.dispatchTouchEvent(event) + views.attachmentPager.dispatchTouchEvent(event) - swipeDismissHandler.onTouch(rootContainer, event) + swipeDismissHandler.onTouch(views.rootContainer, event) isOverlayWasClicked = dispatchOverlayTouch(event) } private fun handleEventActionUp(event: MotionEvent) { // wasDoubleTapped = false - swipeDismissHandler.onTouch(rootContainer, event) - attachmentPager.dispatchTouchEvent(event) + swipeDismissHandler.onTouch(views.rootContainer, event) + views.attachmentPager.dispatchTouchEvent(event) isOverlayWasClicked = dispatchOverlayTouch(event) } @@ -220,12 +224,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun toggleOverlayViewVisibility() { if (systemUiVisibility) { // we hide - TransitionManager.beginDelayedTransition(rootContainer) + TransitionManager.beginDelayedTransition(views.rootContainer) hideSystemUI() overlayView?.isVisible = false } else { // we show - TransitionManager.beginDelayedTransition(rootContainer) + TransitionManager.beginDelayedTransition(views.rootContainer) showSystemUI() overlayView?.isVisible = true } @@ -238,11 +242,11 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi return when (swipeDirection) { SwipeDirection.Up, SwipeDirection.Down -> { if (isSwipeToDismissAllowed && !wasScaled && isImagePagerIdle) { - swipeDismissHandler.onTouch(rootContainer, event) + swipeDismissHandler.onTouch(views.rootContainer, event) } else true } SwipeDirection.Left, SwipeDirection.Right -> { - attachmentPager.dispatchTouchEvent(event) + views.attachmentPager.dispatchTouchEvent(event) } else -> true } @@ -250,8 +254,8 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun handleSwipeViewMove(translationY: Float, translationLimit: Int) { val alpha = calculateTranslationAlpha(translationY, translationLimit) - backgroundView.alpha = alpha - dismissContainer.alpha = alpha + views.backgroundView.alpha = alpha + views.dismissContainer.alpha = alpha overlayView?.alpha = alpha } @@ -265,7 +269,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun createSwipeToDismissHandler() : SwipeToDismissHandler = SwipeToDismissHandler( - swipeView = dismissContainer, + swipeView = views.dismissContainer, shouldAnimateDismiss = { shouldAnimateDismiss() }, onDismiss = { animateClose() }, onSwipeViewMove = ::handleSwipeViewMove) diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 519b8439c9..d72e5bda41 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' apply plugin: 'realm-android' buildscript { @@ -13,10 +13,6 @@ buildscript { } } -androidExtensions { - experimental = true -} - android { compileSdkVersion 29 testOptions.unitTests.includeAndroidResources = true diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt index d89607843f..6759c59237 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.auth.data import android.os.Parcelable import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize @JsonClass(generateAdapter = true) @Parcelize diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt index 4164b84ecd..98a84b8b66 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt @@ -20,7 +20,7 @@ import android.net.Uri import android.os.Parcelable import androidx.exifinterface.media.ExifInterface import com.squareup.moshi.JsonClass -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType @Parcelize diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt index 1e18887008..5d119bb617 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.auth.registration import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize /** * This class represent a localized privacy policy for registration Flow. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt index b77006aa3a..c071384df4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.attachments import android.os.Parcelable import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? { // Check the validity of some fields diff --git a/multipicker/build.gradle b/multipicker/build.gradle index 7c29a5539f..c58c4586b2 100644 --- a/multipicker/build.gradle +++ b/multipicker/build.gradle @@ -16,7 +16,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' android { compileSdkVersion 29 diff --git a/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl b/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl index 7e6eac65c8..403d4bce1c 100644 --- a/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl +++ b/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl @@ -3,7 +3,7 @@ package ${escapeKotlinIdentifiers(packageName)} import android.os.Bundle <#if createFragmentArgs> import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import com.airbnb.mvrx.args import android.view.View diff --git a/vector/build.gradle b/vector/build.gradle index f526e31b60..ce2d9f4c97 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -3,17 +3,13 @@ import com.android.build.OutputFile apply plugin: 'com.android.application' apply plugin: 'com.google.android.gms.oss-licenses-plugin' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-kapt' kapt { correctErrorTypes = true } -androidExtensions { - experimental = true -} - // Note: 2 digits max for each value ext.versionMajor = 1 ext.versionMinor = 0 @@ -280,6 +276,10 @@ android { java.srcDirs += "src/sharedTest/java" } } + + buildFeatures { + viewBinding true + } } dependencies { diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt index 6c4bb925dd..fb87ba6299 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt @@ -24,7 +24,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.snackbar.Snackbar import im.vector.app.R import im.vector.app.core.utils.toast -import kotlinx.android.synthetic.debug.activity_test_material_theme.* + // Rendering is not the same with VectorBaseActivity abstract class DebugMaterialThemeActivity : AppCompatActivity() { diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 1d9de30a0f..6700e7f5e6 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -21,6 +21,7 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.content.Intent import android.os.Build +import android.view.LayoutInflater import androidx.core.app.NotificationCompat import androidx.core.app.Person import androidx.core.content.getSystemService @@ -34,16 +35,17 @@ import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.toast +import im.vector.app.databinding.ActivityDebugMenuBinding import im.vector.app.features.debug.sas.DebugSasEmojiActivity import im.vector.app.features.qrcode.QrCodeScannerActivity import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData -import kotlinx.android.synthetic.debug.activity_debug_menu.* + import timber.log.Timber import javax.inject.Inject -class DebugMenuActivity : VectorBaseActivity() { +class DebugMenuActivity : VectorBaseActivity() { - override fun getLayoutRes() = R.layout.activity_debug_menu + override fun getBinding() = ActivityDebugMenuBinding.inflate(layoutInflater) @Inject lateinit var activeSessionHolder: ActiveSessionHolder @@ -69,17 +71,17 @@ class DebugMenuActivity : VectorBaseActivity() { } private fun setupViews() { - debug_test_text_view_link.setOnClickListener { testTextViewLink() } - debug_show_sas_emoji.setOnClickListener { showSasEmoji() } - debug_test_notification.setOnClickListener { testNotification() } - debug_test_material_theme_light.setOnClickListener { testMaterialThemeLight() } - debug_test_material_theme_dark.setOnClickListener { testMaterialThemeDark() } - debug_test_crash.setOnClickListener { testCrash() } - debug_scan_qr_code.setOnClickListener { scanQRCode() } + views.debugTestTextViewLink.setOnClickListener { testTextViewLink() } + views.debugShowSasEmoji.setOnClickListener { showSasEmoji() } + views.debugTestNotification.setOnClickListener { testNotification() } + views.debugTestMaterialThemeLight.setOnClickListener { testMaterialThemeLight() } + views.debugTestMaterialThemeDark.setOnClickListener { testMaterialThemeDark() } + views.debugTestCrash.setOnClickListener { testCrash() } + views.debugScanQrCode.setOnClickListener { scanQRCode() } } private fun renderQrCode(text: String) { - debug_qr_code.setData(text) + views.debugQrCode.setData(text) } private fun testTextViewLink() { diff --git a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt index 8b7a431435..ce1deef104 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt @@ -22,7 +22,7 @@ import android.view.ViewGroup import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import im.vector.app.R -import kotlinx.android.synthetic.debug.activity_test_linkify.* + class TestLinkifyActivity : AppCompatActivity() { diff --git a/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt index 869058eff6..7871fa0971 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt @@ -22,7 +22,7 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis -import kotlinx.android.synthetic.main.fragment_generic_recycler.* + class DebugSasEmojiActivity : AppCompatActivity() { @@ -30,12 +30,12 @@ class DebugSasEmojiActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.fragment_generic_recycler) val controller = SasEmojiController() - genericRecyclerView.configureWith(controller) + views.genericRecyclerView.configureWith(controller) controller.setData(SasState(getAllVerificationEmojis())) } override fun onDestroy() { - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() super.onDestroy() } } diff --git a/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt b/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt index 0d9fb9d93d..ca1e9a2a2d 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt @@ -21,7 +21,7 @@ import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import im.vector.app.R -import kotlinx.android.synthetic.main.dialog_confirmation_with_reason.view.* + object ConfirmationDialogBuilder { diff --git a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt index 53c2b7fc6c..ef191d5110 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt @@ -31,7 +31,7 @@ fun ComponentActivity.registerStartForActivityResult(onResult: (ActivityResult) return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult) } -fun VectorBaseActivity.addFragment( +fun VectorBaseActivity<*>.addFragment( frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false @@ -39,7 +39,7 @@ fun VectorBaseActivity.addFragment( supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseActivity.addFragment( +fun VectorBaseActivity<*>.addFragment( frameId: Int, fragmentClass: Class, params: Parcelable? = null, @@ -51,7 +51,7 @@ fun VectorBaseActivity.addFragment( } } -fun VectorBaseActivity.replaceFragment( +fun VectorBaseActivity<*>.replaceFragment( frameId: Int, fragment: Fragment, tag: String? = null, @@ -60,7 +60,7 @@ fun VectorBaseActivity.replaceFragment( supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseActivity.replaceFragment( +fun VectorBaseActivity<*>.replaceFragment( frameId: Int, fragmentClass: Class, params: Parcelable? = null, @@ -72,7 +72,7 @@ fun VectorBaseActivity.replaceFragment( } } -fun VectorBaseActivity.addFragmentToBackstack( +fun VectorBaseActivity<*>.addFragmentToBackstack( frameId: Int, fragment: Fragment, tag: String? = null, @@ -81,19 +81,19 @@ fun VectorBaseActivity.addFragmentToBackstack( supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } -fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, - fragmentClass: Class, - params: Parcelable? = null, - tag: String? = null, - allowStateLoss: Boolean = false, - option: ((FragmentTransaction) -> Unit)? = null) { +fun VectorBaseActivity<*>.addFragmentToBackstack(frameId: Int, + fragmentClass: Class, + params: Parcelable? = null, + tag: String? = null, + allowStateLoss: Boolean = false, + option: ((FragmentTransaction) -> Unit)? = null) { supportFragmentManager.commitTransaction(allowStateLoss) { option?.invoke(this) replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) } } -fun VectorBaseActivity.hideKeyboard() { +fun VectorBaseActivity<*>.hideKeyboard() { currentFocus?.hideKeyboard() } diff --git a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt index 2740d5393a..21760da7ed 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt @@ -23,6 +23,7 @@ import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment +import com.airbnb.mvrx.BaseMvRxFragment import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.selectTxtFileToWrite @@ -34,7 +35,7 @@ fun Fragment.registerStartForActivityResult(onResult: (ActivityResult) -> Unit): return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult) } -fun VectorBaseFragment.addFragment( +fun Fragment.addFragment( frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false @@ -42,7 +43,7 @@ fun VectorBaseFragment.addFragment( parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) } } -fun VectorBaseFragment.addFragment( +fun VectorBaseFragment<*>.addFragment( frameId: Int, fragmentClass: Class, params: Parcelable? = null, @@ -54,7 +55,7 @@ fun VectorBaseFragment.addFragment( } } -fun VectorBaseFragment.replaceFragment( +fun Fragment.replaceFragment( frameId: Int, fragment: Fragment, allowStateLoss: Boolean = false @@ -62,7 +63,7 @@ fun VectorBaseFragment.replaceFragment( parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) } } -fun VectorBaseFragment.replaceFragment( +fun VectorBaseFragment<*>.replaceFragment( frameId: Int, fragmentClass: Class, params: Parcelable? = null, @@ -74,7 +75,7 @@ fun VectorBaseFragment.replaceFragment( } } -fun VectorBaseFragment.addFragmentToBackstack( +fun Fragment.addFragmentToBackstack( frameId: Int, fragment: Fragment, tag: String? = null, @@ -83,7 +84,7 @@ fun VectorBaseFragment.addFragmentToBackstack( parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) } } -fun VectorBaseFragment.addFragmentToBackstack( +fun VectorBaseFragment<*>.addFragmentToBackstack( frameId: Int, fragmentClass: Class, params: Parcelable? = null, @@ -95,7 +96,7 @@ fun VectorBaseFragment.addFragmentToBackstack( } } -fun VectorBaseFragment.addChildFragment( +fun Fragment.addChildFragment( frameId: Int, fragment: Fragment, tag: String? = null, @@ -104,7 +105,7 @@ fun VectorBaseFragment.addChildFragment( childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) } } -fun VectorBaseFragment.addChildFragment( +fun VectorBaseFragment<*>.addChildFragment( frameId: Int, fragmentClass: Class, params: Parcelable? = null, @@ -116,7 +117,7 @@ fun VectorBaseFragment.addChildFragment( } } -fun VectorBaseFragment.replaceChildFragment( +fun Fragment.replaceChildFragment( frameId: Int, fragment: Fragment, tag: String? = null, @@ -125,7 +126,7 @@ fun VectorBaseFragment.replaceChildFragment( childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } } -fun VectorBaseFragment.replaceChildFragment( +fun VectorBaseFragment<*>.replaceChildFragment( frameId: Int, fragmentClass: Class, params: Parcelable? = null, @@ -137,7 +138,7 @@ fun VectorBaseFragment.replaceChildFragment( } } -fun VectorBaseFragment.addChildFragmentToBackstack( +fun Fragment.addChildFragmentToBackstack( frameId: Int, fragment: Fragment, tag: String? = null, @@ -146,7 +147,7 @@ fun VectorBaseFragment.addChildFragmentToBackstack( childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } } -fun VectorBaseFragment.addChildFragmentToBackstack( +fun VectorBaseFragment<*>.addChildFragmentToBackstack( frameId: Int, fragmentClass: Class, params: Parcelable? = null, diff --git a/vector/src/main/java/im/vector/app/core/platform/ButtonStateView.kt b/vector/src/main/java/im/vector/app/core/platform/ButtonStateView.kt index cb05a2ac7d..254723a282 100755 --- a/vector/src/main/java/im/vector/app/core/platform/ButtonStateView.kt +++ b/vector/src/main/java/im/vector/app/core/platform/ButtonStateView.kt @@ -25,7 +25,7 @@ import android.widget.FrameLayout import androidx.core.view.isInvisible import androidx.core.view.isVisible import im.vector.app.R -import kotlinx.android.synthetic.main.view_button_state.view.* + class ButtonStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : FrameLayout(context, attrs, defStyle) { diff --git a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt index 76baf347f9..8574073f39 100644 --- a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt @@ -15,23 +15,24 @@ */ package im.vector.app.core.platform +import android.view.LayoutInflater import androidx.annotation.CallSuper import androidx.core.view.isGone import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.hideKeyboard -import kotlinx.android.synthetic.main.activity.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import im.vector.app.databinding.ActivityBinding + import org.matrix.android.sdk.api.session.Session import javax.inject.Inject /** * Simple activity with a toolbar, a waiting overlay, and a fragment container and a session. */ -abstract class SimpleFragmentActivity : VectorBaseActivity() { +abstract class SimpleFragmentActivity : VectorBaseActivity() { - override fun getLayoutRes() = R.layout.activity + override fun getBinding() = ActivityBinding.inflate(layoutInflater) @Inject lateinit var session: Session @@ -41,8 +42,8 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() { } override fun initUiAndData() { - configureToolbar(toolbar) - waitingView = findViewById(R.id.waiting_view) + configureToolbar(views.toolbar) + waitingView = views.overlayWaitingView.waitingView } /** @@ -51,21 +52,21 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() { */ fun updateWaitingView(data: WaitingViewData?) { data?.let { - waitingStatusText.text = data.message + views.overlayWaitingView.waitingStatusText.text = data.message if (data.progress != null && data.progressTotal != null) { - waitingHorizontalProgress.isIndeterminate = false - waitingHorizontalProgress.progress = data.progress - waitingHorizontalProgress.max = data.progressTotal - waitingHorizontalProgress.isVisible = true - waitingCircularProgress.isVisible = false + views.overlayWaitingView.waitingHorizontalProgress.isIndeterminate = false + views.overlayWaitingView.waitingHorizontalProgress.progress = data.progress + views.overlayWaitingView.waitingHorizontalProgress.max = data.progressTotal + views.overlayWaitingView.waitingHorizontalProgress.isVisible = true + views.overlayWaitingView.waitingCircularProgress.isVisible = false } else if (data.isIndeterminate) { - waitingHorizontalProgress.isIndeterminate = true - waitingHorizontalProgress.isVisible = true - waitingCircularProgress.isVisible = false + views.overlayWaitingView.waitingHorizontalProgress.isIndeterminate = true + views.overlayWaitingView.waitingHorizontalProgress.isVisible = true + views.overlayWaitingView.waitingCircularProgress.isVisible = false } else { - waitingHorizontalProgress.isVisible = false - waitingCircularProgress.isVisible = true + views.overlayWaitingView.waitingHorizontalProgress.isVisible = false + views.overlayWaitingView.waitingCircularProgress.isVisible = true } showWaitingView() @@ -76,15 +77,15 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() { override fun showWaitingView() { hideKeyboard() - waitingStatusText.isGone = waitingStatusText.text.isNullOrBlank() + views.overlayWaitingView.waitingStatusText.isGone = views.overlayWaitingView.waitingStatusText.text.isNullOrBlank() super.showWaitingView() } override fun hideWaitingView() { - waitingStatusText.text = null - waitingStatusText.isGone = true - waitingHorizontalProgress.progress = 0 - waitingHorizontalProgress.isVisible = false + views.overlayWaitingView.waitingStatusText.text = null + views.overlayWaitingView.waitingStatusText.isGone = true + views.overlayWaitingView.waitingHorizontalProgress.progress = 0 + views.overlayWaitingView.waitingHorizontalProgress.isVisible = false super.hideWaitingView() } diff --git a/vector/src/main/java/im/vector/app/core/platform/StateView.kt b/vector/src/main/java/im/vector/app/core/platform/StateView.kt index 57f5a11a91..f753b640a0 100755 --- a/vector/src/main/java/im/vector/app/core/platform/StateView.kt +++ b/vector/src/main/java/im/vector/app/core/platform/StateView.kt @@ -24,7 +24,7 @@ import android.widget.FrameLayout import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.extensions.updateConstraintSet -import kotlinx.android.synthetic.main.view_state.view.* + class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : FrameLayout(context, attrs, defStyle) { diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 4006137ee9..56ac8d4078 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -21,24 +21,26 @@ import android.content.Context import android.content.res.Configuration import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View import android.view.WindowManager import androidx.annotation.AttrRes import androidx.annotation.CallSuper -import androidx.annotation.LayoutRes import androidx.annotation.MainThread import androidx.annotation.MenuRes import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar +import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentFactory import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider +import androidx.viewbinding.ViewBinding import com.airbnb.mvrx.MvRx import com.bumptech.glide.util.Util import com.google.android.material.snackbar.Snackbar @@ -79,13 +81,19 @@ import im.vector.app.receivers.DebugReceiver import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable -import kotlinx.android.synthetic.main.activity.* + import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.failure.GlobalError import timber.log.Timber import kotlin.system.measureTimeMillis -abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { +abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { + /* ========================================================================================== + * View + * ========================================================================================== */ + + protected lateinit var views: VB + /* ========================================================================================== * View model * ========================================================================================== */ @@ -210,9 +218,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { // Hack for font size applyFontSize() - if (getLayoutRes() != -1) { - setContentView(getLayoutRes()) - } + views = getBinding() + setContentView(views.root) this.savedInstanceState = savedInstanceState @@ -450,7 +457,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { } private fun recursivelyDispatchOnBackPressed(fm: FragmentManager, fromToolbar: Boolean): Boolean { - val reverseOrder = fm.fragments.filterIsInstance().reversed() + val reverseOrder = fm.fragments.filterIsInstance>().reversed() for (f in reverseOrder) { val handledByChildFragments = recursivelyDispatchOnBackPressed(f.childFragmentManager, fromToolbar) if (handledByChildFragments) { @@ -537,8 +544,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { * OPEN METHODS * ========================================================================================== */ - @LayoutRes - open fun getLayoutRes() = -1 + abstract fun getBinding(): VB open fun displayInFullscreen() = false @@ -565,13 +571,13 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { * ========================================================================================== */ fun showSnackbar(message: String) { - coordinatorLayout?.let { + getCoordinatorLayout()?.let { Snackbar.make(it, message, Snackbar.LENGTH_SHORT).show() } } fun showSnackbar(message: String, @StringRes withActionTitle: Int?, action: (() -> Unit)?) { - coordinatorLayout?.let { + getCoordinatorLayout()?.let { Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply { withActionTitle?.let { setAction(withActionTitle, { action?.invoke() }) @@ -580,6 +586,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { } } + // TODO BMA Provide the CL from the Views + open fun getCoordinatorLayout(): CoordinatorLayout? = null + /* ========================================================================================== * User Consent * ========================================================================================== */ diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt index 74e9afb651..4190ff228f 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt @@ -27,6 +27,7 @@ import android.widget.FrameLayout import androidx.annotation.CallSuper import androidx.annotation.LayoutRes import androidx.lifecycle.ViewModelProvider +import androidx.viewbinding.ViewBinding import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.MvRxView import com.airbnb.mvrx.MvRxViewId @@ -46,7 +47,7 @@ import java.util.concurrent.TimeUnit /** * Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment) */ -abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView { +abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView { private val mvrxViewIdProperty = MvRxViewId() final override val mvrxViewId: String by mvrxViewIdProperty @@ -56,8 +57,13 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment() * View * ========================================================================================== */ - @LayoutRes - abstract fun getLayoutResId(): Int + private var _binding: VB? = null + + // This property is only valid between onCreateView and onDestroyView. + protected val views: VB + get() = _binding!! + + abstract fun getBinding(inflater: LayoutInflater, container: ViewGroup?): VB /* ========================================================================================== * View model @@ -77,8 +83,8 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment() private var bottomSheetBehavior: BottomSheetBehavior? = null - val vectorBaseActivity: VectorBaseActivity by lazy { - activity as VectorBaseActivity + val vectorBaseActivity: VectorBaseActivity<*> by lazy { + activity as VectorBaseActivity<*> } open val showExpanded = false @@ -102,7 +108,8 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment() } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(getLayoutResId(), container, false) + _binding = getBinding(inflater, container) + return views.root } @CallSuper diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt index ffaee5075f..7ca3469282 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt @@ -33,6 +33,7 @@ import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.Toolbar import androidx.lifecycle.ViewModelProvider +import androidx.viewbinding.ViewBinding import com.airbnb.mvrx.BaseMvRxFragment import com.airbnb.mvrx.MvRx import com.bumptech.glide.util.Util.assertMainThread @@ -48,14 +49,14 @@ import im.vector.app.features.navigation.Navigator import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable -import kotlinx.android.synthetic.main.activity.* + import timber.log.Timber import java.util.concurrent.TimeUnit -abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { +abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { - protected val vectorBaseActivity: VectorBaseActivity by lazy { - activity as VectorBaseActivity + protected val vectorBaseActivity: VectorBaseActivity<*> by lazy { + activity as VectorBaseActivity<*> } /* ========================================================================================== @@ -82,6 +83,16 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { protected val fragmentViewModelProvider get() = ViewModelProvider(this, viewModelFactory) + /* ========================================================================================== + * Views + * ========================================================================================== */ + + private var _binding: VB? = null + + // This property is only valid between onCreateView and onDestroyView. + protected val views: VB + get() = _binding!! + /* ========================================================================================== * Life cycle * ========================================================================================== */ @@ -106,11 +117,11 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { Timber.i("onCreateView Fragment ${javaClass.simpleName}") - return inflater.inflate(getLayoutResId(), container, false) + _binding = getBinding(inflater, container) + return views.root } - @LayoutRes - abstract fun getLayoutResId(): Int + abstract fun getBinding(inflater: LayoutInflater, container: ViewGroup?): VB @CallSuper override fun onResume() { @@ -137,6 +148,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { super.onDestroyView() Timber.i("onDestroyView Fragment ${javaClass.simpleName}") uiDisposables.clear() + _binding = null } override fun onDestroy() { @@ -174,6 +186,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { arguments = args.toMvRxBundle() } + // TODO BMA Extract this and use simple type in Fragment.kt fun Parcelable?.toMvRxBundle(): Bundle? { return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } } } @@ -186,7 +199,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { } protected fun showErrorInSnackbar(throwable: Throwable) { - vectorBaseActivity.coordinatorLayout?.let { + vectorBaseActivity.getCoordinatorLayout()?.let { Snackbar.make(it, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT) .show() } diff --git a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt index ab4a781aab..a2318e3608 100644 --- a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt +++ b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGeneric.kt @@ -17,41 +17,47 @@ package im.vector.app.core.ui.bottomsheet import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.annotation.CallSuper import androidx.recyclerview.widget.RecyclerView import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment -import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject /** * Generic Bottom sheet with actions */ abstract class BottomSheetGeneric : - VectorBaseBottomSheetDialogFragment(), + VectorBaseBottomSheetDialogFragment(), BottomSheetGenericController.Listener { @Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool final override val showExpanded = true - final override fun getLayoutResId() = R.layout.bottom_sheet_generic_list + final override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding { + return BottomSheetGenericListBinding.inflate(inflater, container, false) + } abstract fun getController(): BottomSheetGenericController @CallSuper override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bottomSheetRecyclerView.configureWith(getController(), viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) + views.views.bottomSheetRecyclerView.configureWith(getController(), viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) getController().listener = this } @CallSuper override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.views.bottomSheetRecyclerView.cleanup() getController().listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt index d418822b7f..7a09f394d3 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt @@ -29,8 +29,6 @@ import androidx.core.content.withStyledAttributes import androidx.core.view.isGone import androidx.core.view.isInvisible import androidx.core.view.isVisible -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.features.themes.ThemeUtils @@ -41,20 +39,11 @@ class BottomSheetActionButton @JvmOverloads constructor( defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr) { - @BindView(R.id.itemVerificationActionTitle) - lateinit var actionTextView: TextView - - @BindView(R.id.itemVerificationActionSubTitle) - lateinit var descriptionTextView: TextView - - @BindView(R.id.itemVerificationLeftIcon) - lateinit var leftIconImageView: ImageView - - @BindView(R.id.itemVerificationActionIcon) - lateinit var rightIconImageView: ImageView - - @BindView(R.id.itemVerificationClickableZone) - lateinit var clickableView: View + private val actionTextView: TextView + private val descriptionTextView: TextView + private val leftIconImageView: ImageView + private val rightIconImageView: ImageView + private val clickableView: View var title: String? = null set(value) { @@ -116,7 +105,12 @@ class BottomSheetActionButton @JvmOverloads constructor( init { inflate(context, R.layout.item_verification_action, this) - ButterKnife.bind(this) + + actionTextView = findViewById(R.id.itemVerificationActionTitle) + descriptionTextView = findViewById(R.id.itemVerificationActionSubTitle) + leftIconImageView = findViewById(R.id.itemVerificationLeftIcon) + rightIconImageView = findViewById(R.id.itemVerificationActionIcon) + clickableView = findViewById(R.id.itemVerificationClickableZone) context.withStyledAttributes(attrs, R.styleable.BottomSheetActionButton) { title = getString(R.styleable.BottomSheetActionButton_actionTitle) ?: "" diff --git a/vector/src/main/java/im/vector/app/core/ui/views/JumpToReadMarkerView.kt b/vector/src/main/java/im/vector/app/core/ui/views/JumpToReadMarkerView.kt index 3c48637e74..b305d3246e 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/JumpToReadMarkerView.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/JumpToReadMarkerView.kt @@ -22,7 +22,7 @@ import android.view.View import android.widget.RelativeLayout import androidx.core.content.ContextCompat import im.vector.app.R -import kotlinx.android.synthetic.main.view_jump_to_read_marker.view.* + class JumpToReadMarkerView @JvmOverloads constructor( context: Context, diff --git a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt index c935d7662f..478f448e1d 100755 --- a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt @@ -24,7 +24,7 @@ import androidx.core.content.edit import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences -import kotlinx.android.synthetic.main.view_keys_backup_banner.view.* + import timber.log.Timber /** diff --git a/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt b/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt index 4620d7a1fb..ca6ea52aab 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt @@ -28,7 +28,7 @@ import im.vector.app.R import im.vector.app.core.error.ResourceLimitErrorFormatter import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.themes.ThemeUtils -import kotlinx.android.synthetic.main.view_notification_area.view.* + import me.gujun.android.span.span import me.saket.bettermovementmethod.BetterLinkMovementMethod import org.matrix.android.sdk.api.failure.MatrixError diff --git a/vector/src/main/java/im/vector/app/core/ui/views/PasswordStrengthBar.kt b/vector/src/main/java/im/vector/app/core/ui/views/PasswordStrengthBar.kt index 9d3ca6efba..508b28b306 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/PasswordStrengthBar.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/PasswordStrengthBar.kt @@ -22,7 +22,7 @@ import android.widget.LinearLayout import androidx.annotation.IntRange import androidx.core.content.ContextCompat import im.vector.app.R -import kotlinx.android.synthetic.main.view_password_strength_bar.view.* + /** * A password strength bar custom widget diff --git a/vector/src/main/java/im/vector/app/core/ui/views/ReadReceiptsView.kt b/vector/src/main/java/im/vector/app/core/ui/views/ReadReceiptsView.kt index b1ef746ee7..f4d39e3198 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/ReadReceiptsView.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/ReadReceiptsView.kt @@ -26,7 +26,7 @@ import im.vector.app.R import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData import im.vector.app.features.home.room.detail.timeline.item.toMatrixItem -import kotlinx.android.synthetic.main.view_read_receipts.view.* + private const val MAX_RECEIPT_DISPLAYED = 5 private const val MAX_RECEIPT_DESCRIBED = 3 diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index 8499b740f7..0a2bb9d039 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -20,6 +20,7 @@ import android.app.Activity import android.content.Intent import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import androidx.appcompat.app.AlertDialog import androidx.lifecycle.Lifecycle import com.bumptech.glide.Glide @@ -30,6 +31,7 @@ import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.extensions.startSyncing import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.deleteAllFiles +import im.vector.app.databinding.FragmentLoadingBinding import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.ShortcutsHandler import im.vector.app.features.login.LoginActivity @@ -42,7 +44,7 @@ import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.signout.hard.SignedOutActivity import im.vector.app.features.signout.soft.SoftLogoutActivity import im.vector.app.features.ui.UiStateRepository -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -66,7 +68,7 @@ data class MainActivityArgs( * This Activity, when started with argument, is also doing some cleanup when user signs out, * clears cache, is logged out, or is soft logged out */ -class MainActivity : VectorBaseActivity(), UnlockedActivity { +class MainActivity : VectorBaseActivity(), UnlockedActivity { companion object { private const val EXTRA_ARGS = "EXTRA_ARGS" @@ -83,6 +85,8 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity { } } + override fun getBinding() = FragmentLoadingBinding.inflate(layoutInflater) + private lateinit var args: MainActivityArgs @Inject lateinit var notificationDrawerManager: NotificationDrawerManager diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt index 8e830d00a4..eec117bb40 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt @@ -19,15 +19,17 @@ package im.vector.app.features.attachments.preview import android.content.Context import android.content.Intent +import android.view.LayoutInflater import androidx.appcompat.widget.Toolbar import im.vector.app.R import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.features.themes.ActivityOtherThemes import org.matrix.android.sdk.api.session.content.ContentAttachmentData -class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { +class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { companion object { private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS" @@ -51,7 +53,7 @@ class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { override fun getOtherThemes() = ActivityOtherThemes.AttachmentsPreview - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun initUiAndData() { if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt index f67b0946cc..7b560481cd 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt @@ -21,6 +21,7 @@ import android.app.Activity.RESULT_CANCELED import android.app.Activity.RESULT_OK import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View @@ -45,9 +46,10 @@ import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.OnSnapPositionChangeListener import im.vector.app.core.utils.SnapOnScrollListener import im.vector.app.core.utils.attachSnapHelperWithListener +import im.vector.app.databinding.FragmentAttachmentsPreviewBinding import im.vector.app.features.media.createUCropWithDefaultSettings -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_attachments_preview.* +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.content.ContentAttachmentData import java.io.File @@ -62,19 +64,21 @@ class AttachmentsPreviewFragment @Inject constructor( private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController, private val attachmentBigPreviewController: AttachmentBigPreviewController, private val colorProvider: ColorProvider -) : VectorBaseFragment(), AttachmentMiniaturePreviewController.Callback { +) : VectorBaseFragment(), AttachmentMiniaturePreviewController.Callback { private val fragmentArgs: AttachmentsPreviewArgs by args() private val viewModel: AttachmentsPreviewViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_attachments_preview + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentAttachmentsPreviewBinding { + return FragmentAttachmentsPreviewBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) applyInsets() setupRecyclerViews() - setupToolbar(attachmentPreviewerToolbar) - attachmentPreviewerSendButton.setOnClickListener { + setupToolbar(views.attachmentPreviewerToolbar) + views.attachmentPreviewerSendButton.setOnClickListener { setResultAndFinish() } } @@ -120,8 +124,8 @@ class AttachmentsPreviewFragment @Inject constructor( override fun onDestroyView() { super.onDestroyView() - attachmentPreviewerMiniatureList.cleanup() - attachmentPreviewerBigList.cleanup() + views.attachmentPreviewerMiniatureList.cleanup() + views.attachmentPreviewerBigList.cleanup() attachmentMiniaturePreviewController.callback = null } @@ -133,9 +137,9 @@ class AttachmentsPreviewFragment @Inject constructor( } else { attachmentMiniaturePreviewController.setData(state) attachmentBigPreviewController.setData(state) - attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex) - attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex) - attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size) + views.attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex) + views.attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex) + views.attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size) } } @@ -146,17 +150,17 @@ class AttachmentsPreviewFragment @Inject constructor( private fun setResultAndFinish() = withState(viewModel) { (requireActivity() as? AttachmentsPreviewActivity)?.setResultAndFinish( it.attachments, - attachmentPreviewerSendImageOriginalSize.isChecked + views.attachmentPreviewerSendImageOriginalSize.isChecked ) } private fun applyInsets() { view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerBottomContainer) { v, insets -> + ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets -> v.updatePadding(bottom = insets.systemWindowInsetBottom) insets } - ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerToolbar) { v, insets -> + ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerToolbar) { v, insets -> v.updateLayoutParams { topMargin = insets.systemWindowInsetTop } @@ -180,13 +184,13 @@ class AttachmentsPreviewFragment @Inject constructor( private fun setupRecyclerViews() { attachmentMiniaturePreviewController.callback = this - attachmentPreviewerMiniatureList.let { + views.attachmentPreviewerMiniatureList.let { it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) it.setHasFixedSize(true) it.adapter = attachmentMiniaturePreviewController.adapter } - attachmentPreviewerBigList.let { + views.attachmentPreviewerBigList.let { it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) it.attachSnapHelperWithListener( PagerSnapHelper(), diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt index b1a2c65ecf..7646da9516 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt @@ -17,18 +17,24 @@ package im.vector.app.features.call import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.core.view.isVisible import com.airbnb.mvrx.activityViewModel import im.vector.app.R import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment -import kotlinx.android.synthetic.main.bottom_sheet_call_controls.* +import im.vector.app.databinding.BottomSheetCallControlsBinding +import im.vector.app.databinding.BottomSheetGenericListBinding + import me.gujun.android.span.span -class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() { - override fun getLayoutResId() = R.layout.bottom_sheet_call_controls +class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() { + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetCallControlsBinding { + return BottomSheetCallControlsBinding.inflate(inflater, container, false) + } private val callViewModel: VectorCallViewModel by activityViewModel() @@ -39,16 +45,16 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() { renderState(it) } - callControlsSoundDevice.clickableView.debouncedClicks { + views.callControlsSoundDevice.clickableView.debouncedClicks { callViewModel.handle(VectorCallViewActions.SwitchSoundDevice) } - callControlsSwitchCamera.clickableView.debouncedClicks { + views.callControlsSwitchCamera.clickableView.debouncedClicks { callViewModel.handle(VectorCallViewActions.ToggleCamera) dismiss() } - callControlsToggleSDHD.clickableView.debouncedClicks { + views.callControlsToggleSDHD.clickableView.debouncedClicks { callViewModel.handle(VectorCallViewActions.ToggleHDSD) dismiss() } @@ -109,30 +115,30 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() { } private fun renderState(state: VectorCallViewState) { - callControlsSoundDevice.title = getString(R.string.call_select_sound_device) - callControlsSoundDevice.subTitle = when (state.soundDevice) { + views.callControlsSoundDevice.title = getString(R.string.call_select_sound_device) + views.callControlsSoundDevice.subTitle = when (state.soundDevice) { CallAudioManager.SoundDevice.PHONE -> getString(R.string.sound_device_phone) CallAudioManager.SoundDevice.SPEAKER -> getString(R.string.sound_device_speaker) CallAudioManager.SoundDevice.HEADSET -> getString(R.string.sound_device_headset) CallAudioManager.SoundDevice.WIRELESS_HEADSET -> getString(R.string.sound_device_wireless_headset) } - callControlsSwitchCamera.isVisible = state.isVideoCall && state.canSwitchCamera - callControlsSwitchCamera.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back) + views.callControlsSwitchCamera.isVisible = state.isVideoCall && state.canSwitchCamera + views.callControlsSwitchCamera.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back) if (state.isVideoCall) { - callControlsToggleSDHD.isVisible = true + views.callControlsToggleSDHD.isVisible = true if (state.isHD) { - callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off) - callControlsToggleSDHD.subTitle = null - callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled) + views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off) + views.callControlsToggleSDHD.subTitle = null + views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled) } else { - callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on) - callControlsToggleSDHD.subTitle = null - callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd) + views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on) + views.callControlsToggleSDHD.subTitle = null + views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd) } } else { - callControlsToggleSDHD.isVisible = false + views.callControlsToggleSDHD.isVisible = false } } } diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt index 81cc077f03..9b36042ff4 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt @@ -18,11 +18,13 @@ package im.vector.app.features.call import android.content.Context import android.util.AttributeSet +import android.view.View +import android.widget.ImageView import android.widget.LinearLayout import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import im.vector.app.R -import kotlinx.android.synthetic.main.view_call_controls.view.* + import org.matrix.android.sdk.api.session.call.CallState import org.webrtc.PeerConnection @@ -30,19 +32,40 @@ class CallControlsView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { + private var ringingControls: View + private var connectedControls: View + + private val ringingControlAccept: View + private var ringingControlDecline: View + private var iv_end_call: View + private var muteIcon: ImageView + private var videoToggleIcon: ImageView + private var iv_leftMiniControl: View + private var iv_more: View + var interactionListener: InteractionListener? = null init { - ConstraintLayout.inflate(context, R.layout.view_call_controls, this) + View.inflate(context, R.layout.view_call_controls, this) // layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - ringingControlAccept.setOnClickListener { acceptIncomingCall() } - ringingControlDecline.setOnClickListener { declineIncomingCall() } - iv_end_call.setOnClickListener { endOngoingCall() } - muteIcon.setOnClickListener { toggleMute() } - videoToggleIcon.setOnClickListener { toggleVideo() } - iv_leftMiniControl.setOnClickListener { returnToChat() } - iv_more.setOnClickListener { moreControlOption() } + ringingControlAccept = findViewById(R.id.ringingControlAccept) + .also { it.setOnClickListener { acceptIncomingCall() } } + ringingControlDecline = findViewById(R.id.ringingControlDecline) + .also { it.setOnClickListener { declineIncomingCall() } } + iv_end_call = findViewById(R.id.iv_end_call) + .also { it.setOnClickListener { endOngoingCall() } } + muteIcon = findViewById(R.id.muteIcon) + .also { it.setOnClickListener { toggleMute() } } + videoToggleIcon = findViewById(R.id.videoToggleIcon) + .also { it.setOnClickListener { toggleVideo() } } + iv_leftMiniControl = findViewById(R.id.iv_leftMiniControl) + .also { it.setOnClickListener { returnToChat() } } + iv_more = findViewById(R.id.iv_more) + .also { it.setOnClickListener { moreControlOption() } } + + ringingControls = findViewById(R.id.ringingControls) + connectedControls = findViewById(R.id.connectedControls) } private fun acceptIncomingCall() { diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index aee882fedf..254a9fa017 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -23,6 +23,7 @@ import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP import android.os.Build import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View import android.view.Window import android.view.WindowManager @@ -44,12 +45,13 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions +import im.vector.app.databinding.ActivityCallBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.RoomDetailArgs import io.reactivex.android.schedulers.AndroidSchedulers -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.activity_call.* +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.EglUtils import org.matrix.android.sdk.api.session.call.MxCallDetail @@ -70,9 +72,9 @@ data class CallArgs( val isVideoCall: Boolean ) : Parcelable -class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionListener { +class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionListener { - override fun getLayoutRes() = R.layout.activity_call + override fun getBinding() = ActivityCallBinding.inflate(layoutInflater) @Inject lateinit var avatarRenderer: AvatarRenderer @@ -147,7 +149,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis super.onCreate(savedInstanceState) // This will need to be refined - ViewCompat.setOnApplyWindowInsetsListener(constraintLayout) { v, insets -> + ViewCompat.setOnApplyWindowInsetsListener(views.constraintLayout) { v, insets -> v.updatePadding(bottom = if (systemUiVisibility) insets.systemWindowInsetBottom else 0) insets } @@ -167,7 +169,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis turnScreenOnAndKeyguardOff() } - constraintLayout.clicks() + views.constraintLayout.clicks() .throttleFirst(300, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe { toggleUiSystemVisibility() } @@ -199,10 +201,10 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis } override fun onDestroy() { - peerConnectionManager.detachRenderers(listOf(pipRenderer, fullscreenRenderer)) + peerConnectionManager.detachRenderers(listOf(views.pipRenderer, views.fullscreenRenderer)) if (surfaceRenderersAreInitialized) { - pipRenderer.release() - fullscreenRenderer.release() + views.pipRenderer.release() + views.fullscreenRenderer.release() } turnScreenOffAndKeyguardOn() super.onDestroy() @@ -217,54 +219,54 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis return } - callControlsView.updateForState(state) + views.callControlsView.updateForState(state) val callState = state.callState.invoke() - callConnectingProgress.isVisible = false + views.callConnectingProgress.isVisible = false when (callState) { is CallState.Idle, is CallState.Dialing -> { - callVideoGroup.isInvisible = true - callInfoGroup.isVisible = true - callStatusText.setText(R.string.call_ring) + views.callVideoGroup.isInvisible = true + views.callInfoGroup.isVisible = true + views.callStatusText.setText(R.string.call_ring) configureCallInfo(state) } is CallState.LocalRinging -> { - callVideoGroup.isInvisible = true - callInfoGroup.isVisible = true - callStatusText.text = null + views.callVideoGroup.isInvisible = true + views.callInfoGroup.isVisible = true + views.callStatusText.text = null configureCallInfo(state) } is CallState.Answering -> { - callVideoGroup.isInvisible = true - callInfoGroup.isVisible = true - callStatusText.setText(R.string.call_connecting) - callConnectingProgress.isVisible = true + views.callVideoGroup.isInvisible = true + views.callInfoGroup.isVisible = true + views.callStatusText.setText(R.string.call_connecting) + views.callConnectingProgress.isVisible = true configureCallInfo(state) } is CallState.Connected -> { if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) { if (callArgs.isVideoCall) { - callVideoGroup.isVisible = true - callInfoGroup.isVisible = false - pipRenderer.isVisible = !state.isVideoCaptureInError + views.callVideoGroup.isVisible = true + views.callInfoGroup.isVisible = false + views.pipRenderer.isVisible = !state.isVideoCaptureInError } else { - callVideoGroup.isInvisible = true - callInfoGroup.isVisible = true + views.callVideoGroup.isInvisible = true + views.callInfoGroup.isVisible = true configureCallInfo(state) - callStatusText.text = null + views.callStatusText.text = null } } else { // This state is not final, if you change network, new candidates will be sent - callVideoGroup.isInvisible = true - callInfoGroup.isVisible = true + views.callVideoGroup.isInvisible = true + views.callInfoGroup.isVisible = true configureCallInfo(state) - callStatusText.setText(R.string.call_connecting) - callConnectingProgress.isVisible = true + views.callStatusText.setText(R.string.call_connecting) + views.callConnectingProgress.isVisible = true } // ensure all attached? - peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer, null) + peerConnectionManager.attachViewRenderers(views.pipRenderer, views.fullscreenRenderer, null) } is CallState.Terminated -> { finish() @@ -276,14 +278,14 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis private fun configureCallInfo(state: VectorCallViewState) { state.otherUserMatrixItem.invoke()?.let { - avatarRenderer.render(it, otherMemberAvatar) - participantNameText.text = it.getBestName() - callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call) + avatarRenderer.render(it, views.otherMemberAvatar) + views.participantNameText.text = it.getBestName() + views.callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call) } } private fun configureCallViews() { - callControlsView.interactionListener = this + views.callControlsView.interactionListener = this } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { @@ -303,21 +305,24 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis } // Init Picture in Picture renderer - pipRenderer.init(rootEglBase!!.eglBaseContext, null) - pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT) + views.pipRenderer.init(rootEglBase!!.eglBaseContext, null) + views.pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT) // Init Full Screen renderer - fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null) - fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT) + views.fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null) + views.fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT) - pipRenderer.setZOrderMediaOverlay(true) - pipRenderer.setEnableHardwareScaler(true /* enabled */) - fullscreenRenderer.setEnableHardwareScaler(true /* enabled */) + views.pipRenderer.setZOrderMediaOverlay(true) + views.pipRenderer.setEnableHardwareScaler(true /* enabled */) + views.fullscreenRenderer.setEnableHardwareScaler(true /* enabled */) - peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer, - intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() }) + peerConnectionManager.attachViewRenderers( + views.pipRenderer, + views.fullscreenRenderer, + intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() } + ) - pipRenderer.setOnClickListener { + views.pipRenderer.setOnClickListener { callViewModel.handle(VectorCallViewActions.ToggleCamera) } surfaceRenderersAreInitialized = true diff --git a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt index 43b41f7b5a..478cc676db 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View import android.widget.FrameLayout import androidx.core.view.isVisible @@ -31,8 +32,9 @@ import com.facebook.react.modules.core.PermissionListener import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.platform.VectorBaseActivity -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.activity_jitsi.* +import im.vector.app.databinding.ActivityJitsiBinding +import kotlinx.parcelize.Parcelize + import org.jitsi.meet.sdk.JitsiMeetActivityDelegate import org.jitsi.meet.sdk.JitsiMeetActivityInterface import org.jitsi.meet.sdk.JitsiMeetConferenceOptions @@ -42,7 +44,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull import java.net.URL import javax.inject.Inject -class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, JitsiMeetViewListener { +class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, JitsiMeetViewListener { @Parcelize data class Args( @@ -51,7 +53,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji val enableVideo: Boolean ) : Parcelable - override fun getLayoutRes() = R.layout.activity_jitsi + override fun getBinding() = ActivityJitsiBinding.inflate(layoutInflater) @Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory @@ -76,7 +78,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji super.initUiAndData() jitsiMeetView = JitsiMeetView(this) val params = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) - jitsi_layout.addView(jitsiMeetView, params) + views.jitsiLayout.addView(jitsiMeetView, params) jitsiMeetView?.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt index 6c3ec06f75..a99275d439 100644 --- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt +++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.contactsbook import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import com.airbnb.mvrx.activityViewModel @@ -29,12 +31,14 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentAttachmentsPreviewBinding +import im.vector.app.databinding.FragmentContactsBookBinding import im.vector.app.features.userdirectory.PendingInvitee import im.vector.app.features.userdirectory.UserListAction import im.vector.app.features.userdirectory.UserListSharedAction import im.vector.app.features.userdirectory.UserListSharedActionViewModel import im.vector.app.features.userdirectory.UserListViewModel -import kotlinx.android.synthetic.main.fragment_contacts_book.* + import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.user.model.User import java.util.concurrent.TimeUnit @@ -43,9 +47,12 @@ import javax.inject.Inject class ContactsBookFragment @Inject constructor( val contactsBookViewModelFactory: ContactsBookViewModel.Factory, private val contactsBookController: ContactsBookController -) : VectorBaseFragment(), ContactsBookController.Callback { +) : VectorBaseFragment(), ContactsBookController.Callback { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentContactsBookBinding { + return FragmentContactsBookBinding.inflate(inflater, container, false) + } - override fun getLayoutResId() = R.layout.fragment_contacts_book private val viewModel: UserListViewModel by activityViewModel() // Use activityViewModel to avoid loading several times the data @@ -64,7 +71,7 @@ class ContactsBookFragment @Inject constructor( } private fun setupConsentView() { - phoneBookSearchForMatrixContacts.setOnClickListener { + views.phoneBookSearchForMatrixContacts.setOnClickListener { withState(contactsBookViewModel) { state -> AlertDialog.Builder(requireActivity()) .setTitle(R.string.identity_server_consent_dialog_title) @@ -79,7 +86,7 @@ class ContactsBookFragment @Inject constructor( } private fun setupOnlyBoundContactsView() { - phoneBookOnlyBoundContacts.checkedChanges() + views.phoneBookOnlyBoundContacts.checkedChanges() .subscribe { contactsBookViewModel.handle(ContactsBookAction.OnlyBoundContacts(it)) } @@ -87,7 +94,7 @@ class ContactsBookFragment @Inject constructor( } private fun setupFilterView() { - phoneBookFilter + views.phoneBookFilter .textChanges() .skipInitialValue() .debounce(300, TimeUnit.MILLISECONDS) @@ -98,25 +105,25 @@ class ContactsBookFragment @Inject constructor( } override fun onDestroyView() { - phoneBookRecyclerView.cleanup() + views.phoneBookRecyclerView.cleanup() contactsBookController.callback = null super.onDestroyView() } private fun setupRecyclerView() { contactsBookController.callback = this - phoneBookRecyclerView.configureWith(contactsBookController) + views.phoneBookRecyclerView.configureWith(contactsBookController) } private fun setupCloseView() { - phoneBookClose.debouncedClicks { + views.phoneBookClose.debouncedClicks { sharedActionViewModel.post(UserListSharedAction.GoBack) } } override fun invalidate() = withState(contactsBookViewModel) { state -> - phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent - phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved + views.phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent + views.phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved contactsBookController.setData(state) } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 6fafe0b977..7f0ec3ebc2 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -51,7 +51,7 @@ import im.vector.app.features.userdirectory.UserListSharedAction import im.vector.app.features.userdirectory.UserListSharedActionViewModel import im.vector.app.features.userdirectory.UserListViewModel import im.vector.app.features.userdirectory.UserListViewState -import kotlinx.android.synthetic.main.activity.* + import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure import java.net.HttpURLConnection diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt index 3fee3a3285..83ce9cfe84 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt @@ -16,6 +16,8 @@ package im.vector.app.features.createdirect +import android.view.LayoutInflater +import android.view.ViewGroup import android.widget.Toast import com.airbnb.mvrx.activityViewModel import com.google.zxing.Result @@ -26,19 +28,23 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.registerForPermissionsResult +import im.vector.app.databinding.FragmentAttachmentsPreviewBinding +import im.vector.app.databinding.FragmentQrCodeScannerBinding import im.vector.app.features.userdirectory.PendingInvitee -import kotlinx.android.synthetic.main.fragment_qr_code_scanner.* + import me.dm7.barcodescanner.zxing.ZXingScannerView import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.user.model.User import javax.inject.Inject -class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment(), ZXingScannerView.ResultHandler { +class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment(), ZXingScannerView.ResultHandler { private val viewModel: CreateDirectRoomViewModel by activityViewModel() - override fun getLayoutResId() = R.layout.fragment_qr_code_scanner + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeScannerBinding { + return FragmentQrCodeScannerBinding.inflate(inflater, container, false) + } private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted -> if (allGranted) { @@ -48,14 +54,14 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen private fun startCamera() { // Start camera on resume - scannerView.startCamera() + views.scannerView.startCamera() } override fun onResume() { super.onResume() view?.hideKeyboard() // Register ourselves as a handler for scan results. - scannerView.setResultHandler(this) + views.scannerView.setResultHandler(this) // Start camera on resume if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) { startCamera() @@ -65,9 +71,9 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen override fun onPause() { super.onPause() // Unregister ourselves as a handler for scan results. - scannerView.setResultHandler(null) + views.scannerView.setResultHandler(null) // Stop camera on pause - scannerView.stopCamera() + views.scannerView.stopCamera() } // Copied from https://github.com/markusfisch/BinaryEye/blob/ diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt index 7d2ec839d4..91a0cf25ce 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.keysbackup.restore import android.app.Activity import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer @@ -25,14 +27,18 @@ import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.startImportTextFromFileIntent -import kotlinx.android.synthetic.main.fragment_keys_backup_restore_from_key.* +import im.vector.app.databinding.FragmentAttachmentsPreviewBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding + import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject class KeysBackupRestoreFromKeyFragment @Inject constructor() - : VectorBaseFragment() { + : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_key + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromKeyBinding { + return FragmentKeysBackupRestoreFromKeyBinding.inflate(inflater, container, false) + } private lateinit var viewModel: KeysBackupRestoreFromKeyViewModel private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel @@ -41,8 +47,8 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() super.onViewCreated(view, savedInstanceState) viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromKeyViewModel::class.java) sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java) - mKeyTextEdit.setText(viewModel.recoveryCode.value) - mKeyTextEdit.setOnEditorActionListener { _, actionId, _ -> + views.mKeyTextEdit.setText(viewModel.recoveryCode.value) + views.mKeyTextEdit.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE) { onRestoreFromKey() return@setOnEditorActionListener true @@ -50,14 +56,14 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() return@setOnEditorActionListener false } - mKeyInputLayout.error = viewModel.recoveryCodeErrorText.value + views.mKeyInputLayout.error = viewModel.recoveryCodeErrorText.value viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue -> - mKeyInputLayout.error = newValue + views.mKeyInputLayout.error = newValue }) - keys_restore_button.setOnClickListener { onRestoreFromKey() } - keys_backup_import.setOnClickListener { onImport() } - mKeyTextEdit.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) } + views.keysRestoreButton.setOnClickListener { onRestoreFromKey() } + views.keysBackupImport.setOnClickListener { onImport() } + views.mKeyTextEdit.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) } } private fun onRestoreKeyTextEditChange(s: CharSequence?) { @@ -89,8 +95,8 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor() ?.bufferedReader() ?.use { it.readText() } ?.let { - mKeyTextEdit.setText(it) - mKeyTextEdit.setSelection(it.length) + views.mKeyTextEdit.setText(it) + views.mKeyTextEdit.setSelection(it.length) } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt index 95151b3551..f8b973de12 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.crypto.keysbackup.restore import android.os.Bundle import android.text.SpannableString import android.text.style.ClickableSpan +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.core.text.set import androidx.core.widget.doOnTextChanged @@ -26,12 +28,16 @@ import androidx.lifecycle.Observer import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_keys_backup_restore_from_passphrase.* +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromPassphraseBinding + import javax.inject.Inject -class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment() { +class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_passphrase + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromPassphraseBinding { + return FragmentKeysBackupRestoreFromPassphraseBinding.inflate(inflater, container, false) + } private lateinit var viewModel: KeysBackupRestoreFromPassphraseViewModel private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel @@ -47,18 +53,18 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java) viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue -> - keys_backup_passphrase_enter_til.error = newValue + views.keysBackupPassphraseEnterTil.error = newValue }) - helperTextWithLink.text = spannableStringForHelperText() + views.helperTextWithLink.text = spannableStringForHelperText() viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer { val shouldBeVisible = it ?: false - keys_backup_passphrase_enter_edittext.showPassword(shouldBeVisible) - keys_backup_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) + views.keysBackupPassphraseEnterEdittext.showPassword(shouldBeVisible) + views.keysBackupViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) }) - keys_backup_passphrase_enter_edittext.setOnEditorActionListener { _, actionId, _ -> + views.keysBackupPassphraseEnterEdittext.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE) { onRestoreBackup() return@setOnEditorActionListener true @@ -66,10 +72,10 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase return@setOnEditorActionListener false } - keys_backup_view_show_password.setOnClickListener { toggleVisibilityMode() } - helperTextWithLink.setOnClickListener { onUseRecoveryKey() } - keys_backup_restore_with_passphrase_submit.setOnClickListener { onRestoreBackup() } - keys_backup_passphrase_enter_edittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) } + views.keysBackupViewShowPassword.setOnClickListener { toggleVisibilityMode() } + views.helperTextWithLink.setOnClickListener { onUseRecoveryKey() } + views.keysBackupRestoreWithPassphraseSubmit.setOnClickListener { onRestoreBackup() } + views.keysBackupPassphraseEnterEdittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) } } private fun spannableStringForHelperText(): SpannableString { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt index 902f376ec4..b93f080ddf 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt @@ -16,17 +16,23 @@ package im.vector.app.features.crypto.keysbackup.restore import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.LiveEvent -import kotlinx.android.synthetic.main.fragment_keys_backup_restore_success.* +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreSuccessBinding + import javax.inject.Inject -class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment() { +class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_success + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreSuccessBinding { + return FragmentKeysBackupRestoreSuccessBinding.inflate(inflater, container, false) + } private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel @@ -40,15 +46,15 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen it.totalNumberOfKeys, it.totalNumberOfKeys) val part2 = resources.getQuantityString(R.plurals.keys_backup_restore_success_description_part2, it.successfullyNumberOfImportedKeys, it.successfullyNumberOfImportedKeys) - mSuccessDetailsText.text = String.format("%s\n%s", part1, part2) + views.mSuccessDetailsText.text = String.format("%s\n%s", part1, part2) } // We don't put emoji in string xml as it will crash on old devices - mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title, "🎉") + views.mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title, "🎉") } else { - mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date) - mSuccessDetailsText.isVisible = false + views.mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date) + views.mSuccessDetailsText.isVisible = false } - keys_backup_setup_done_button.setOnClickListener { onDone() } + views.keysBackupSetupDoneButton.setOnClickListener { onDone() } } private fun onDone() { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt index 36ee4d954f..5075280aa9 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt @@ -16,7 +16,9 @@ package im.vector.app.features.crypto.keysbackup.settings import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState @@ -24,28 +26,32 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentKeysBackupSettingsBinding import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity -import kotlinx.android.synthetic.main.fragment_keys_backup_settings.* + import javax.inject.Inject class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController) - : VectorBaseFragment(), + : VectorBaseFragment(), KeysBackupSettingsRecyclerViewController.Listener { - override fun getLayoutResId() = R.layout.fragment_keys_backup_settings + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSettingsBinding { + return FragmentKeysBackupSettingsBinding.inflate(inflater, container, false) + } private val viewModel: KeysBackupSettingsViewModel by activityViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController) + views.keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController) keysBackupSettingsRecyclerViewController.listener = this } override fun onDestroyView() { keysBackupSettingsRecyclerViewController.listener = null - keysBackupSettingsRecyclerView.cleanup() + views.keysBackupSettingsRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt index c3d5c56189..8db392639d 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt @@ -17,17 +17,23 @@ package im.vector.app.features.crypto.keysbackup.setup import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.lifecycle.Observer import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.LiveEvent -import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step1.* +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding + import javax.inject.Inject -class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() { +class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step1 + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep1Binding { + return FragmentKeysBackupSetupStep1Binding.inflate(inflater, container, false) + } private lateinit var viewModel: KeysBackupSetupSharedViewModel @@ -39,12 +45,12 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() viewModel.showManualExport.observe(viewLifecycleOwner, Observer { val showOption = it ?: false // Can't use isVisible because the kotlin compiler will crash with Back-end (JVM) Internal error: wrong code generated - advancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE - manualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE + views.advancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE + views.manualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE }) - keys_backup_setup_step1_button.setOnClickListener { onButtonClick() } - manualExportButton.setOnClickListener { onManualExportClick() } + views.keysBackupSetupStep1Button.setOnClickListener { onButtonClick() } + views.manualExportButton.setOnClickListener { onManualExportClick() } } private fun onButtonClick() { diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt index 93f3b71ced..f81cb09ce0 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt @@ -16,7 +16,9 @@ package im.vector.app.features.crypto.keysbackup.setup import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.core.widget.doOnTextChanged import androidx.lifecycle.Observer @@ -26,15 +28,19 @@ import com.nulabinc.zxcvbn.Zxcvbn import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding import im.vector.app.features.settings.VectorLocale -import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step2.* + import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import javax.inject.Inject -class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() { +class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step2 + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep2Binding { + return FragmentKeysBackupSetupStep2Binding.inflate(inflater, container, false) + } private val zxcvbn = Zxcvbn() diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index 94c9b68606..89c73fbecf 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.crypto.keysbackup.setup import android.app.Activity import android.net.Uri import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog @@ -33,7 +35,9 @@ import im.vector.app.core.utils.LiveEvent import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.selectTxtFileToWrite import im.vector.app.core.utils.startSharePlainTextIntent -import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step3.* +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding + import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -44,9 +48,11 @@ import java.util.Date import java.util.Locale import javax.inject.Inject -class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() { +class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step3 + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep3Binding { + return FragmentKeysBackupSetupStep3Binding.inflate(inflater, container, false) + } private lateinit var viewModel: KeysBackupSetupSharedViewModel diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt index 2abad9dd38..9e7fde370d 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt @@ -35,8 +35,8 @@ import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.features.crypto.recover.SetupMode -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.activity.* +import kotlinx.parcelize.Parcelize + import javax.inject.Inject import kotlin.reflect.KClass diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt index 9fb3f637e1..f2d5bf1940 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.crypto.quads import android.app.Activity import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import com.airbnb.mvrx.activityViewModel import com.jakewharton.rxbinding3.widget.editorActionEvents @@ -27,15 +29,19 @@ import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.startImportTextFromFileIntent +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentSsssAccessFromKeyBinding import io.reactivex.android.schedulers.AndroidSchedulers -import kotlinx.android.synthetic.main.fragment_ssss_access_from_key.* + import org.matrix.android.sdk.api.extensions.tryOrNull import java.util.concurrent.TimeUnit import javax.inject.Inject -class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment() { +class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_ssss_access_from_key + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromKeyBinding { + return FragmentSsssAccessFromKeyBinding.inflate(inflater, container, false) + } val sharedViewModel: SharedSecureStorageViewModel by activityViewModel() diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt index 97047fbc65..370bd92ccf 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.quads import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.core.text.toSpannable import com.airbnb.mvrx.activityViewModel @@ -29,16 +31,20 @@ import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.colorizeMatchingText +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding 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 class SharedSecuredStoragePassphraseFragment @Inject constructor( private val colorProvider: ColorProvider -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_ssss_access_from_passphrase + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromPassphraseBinding { + return FragmentSsssAccessFromPassphraseBinding.inflate(inflater, container, false) + } val sharedViewModel: SharedSecureStorageViewModel by activityViewModel() @@ -48,7 +54,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor( // If has passphrase val pass = getString(R.string.recovery_passphrase) val key = getString(R.string.recovery_key) - ssss_restore_with_passphrase_warning_text.text = getString( + views.ssssRestoreWithPassphraseWarningText.text = getString( R.string.enter_secret_storage_passphrase_or_key, pass, key @@ -57,7 +63,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor( .colorizeMatchingText(pass, colorProvider.getColorFromAttribute(android.R.attr.textColorLink)) .colorizeMatchingText(key, colorProvider.getColorFromAttribute(android.R.attr.textColorLink)) - ssss_passphrase_enter_edittext.editorActionEvents() + views.ssssPassphraseEnterEdittext.editorActionEvents() .throttleFirst(300, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe { @@ -67,40 +73,40 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor( } .disposeOnDestroyView() - ssss_passphrase_enter_edittext.textChanges() + views.ssssPassphraseEnterEdittext.textChanges() .subscribe { - ssss_passphrase_enter_til.error = null - ssss_passphrase_submit.isEnabled = it.isNotBlank() + views.ssssPassphraseEnterTil.error = null + views.ssssPassphraseSubmit.isEnabled = it.isNotBlank() } .disposeOnDestroyView() - ssss_passphrase_reset.clickableView.debouncedClicks { + views.ssssPassphraseReset.clickableView.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll) } sharedViewModel.observeViewEvents { when (it) { is SharedSecureStorageViewEvent.InlineError -> { - ssss_passphrase_enter_til.error = it.message + views.ssssPassphraseEnterTil.error = it.message } } } - ssss_passphrase_submit.debouncedClicks { submit() } - ssss_passphrase_use_key.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) } - ssss_view_show_password.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) } + views.ssssPassphraseSubmit.debouncedClicks { submit() } + views.ssssPassphraseUseKey.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) } + views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) } } fun submit() { - val text = ssss_passphrase_enter_edittext.text.toString() + val text = views.ssssPassphraseEnterEdittext.text.toString() if (text.isBlank()) return // Should not reach this point as button disabled - ssss_passphrase_submit.isEnabled = false + views.ssssPassphraseSubmit.isEnabled = false sharedViewModel.handle(SharedSecureStorageAction.SubmitPassphrase(text)) } override fun invalidate() = withState(sharedViewModel) { state -> val shouldBeVisible = state.passphraseVisible - ssss_passphrase_enter_edittext.showPassword(shouldBeVisible) - ssss_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) + views.ssssPassphraseEnterEdittext.showPassword(shouldBeVisible) + views.ssssViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt index d7db779230..47a73bb325 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt @@ -17,41 +17,48 @@ package im.vector.app.features.crypto.quads import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentSsssResetAllBinding import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet -import kotlinx.android.synthetic.main.fragment_ssss_reset_all.* + import javax.inject.Inject -class SharedSecuredStorageResetAllFragment @Inject constructor() : VectorBaseFragment() { +class SharedSecuredStorageResetAllFragment @Inject constructor() + : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_ssss_reset_all + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssResetAllBinding { + return FragmentSsssResetAllBinding.inflate(inflater, container, false) + } val sharedViewModel: SharedSecureStorageViewModel by activityViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - ssss_reset_button_reset.debouncedClicks { + views.ssssResetButtonReset.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.DoResetAll) } - ssss_reset_button_cancel.debouncedClicks { + views.ssssResetButtonCancel.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.Back) } - ssss_reset_other_devices.debouncedClicks { + views.ssssResetOtherDevices.debouncedClicks { withState(sharedViewModel) { DeviceListBottomSheet.newInstance(it.userId, false).show(childFragmentManager, "DEV_LIST") } } sharedViewModel.subscribe(this) { state -> - ssss_reset_other_devices.setTextOrHide( + views.ssssResetOtherDevices.setTextOrHide( state.activeDeviceCount .takeIf { it > 0 } ?.let { resources.getQuantityString(R.plurals.secure_backup_reset_devices_you_can_verify, it, it) } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapAccountPasswordFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapAccountPasswordFragment.kt index ccf2d67701..6d951c3433 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapAccountPasswordFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapAccountPasswordFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.recover import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.core.text.toSpannable import com.airbnb.mvrx.parentFragmentViewModel @@ -30,18 +32,22 @@ import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.colorizeMatchingText +import im.vector.app.databinding.FragmentBootstrapEnterAccountPasswordBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding 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 + + + import java.util.concurrent.TimeUnit import javax.inject.Inject class BootstrapAccountPasswordFragment @Inject constructor( private val colorProvider: ColorProvider -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_account_password + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterAccountPasswordBinding { + return FragmentBootstrapEnterAccountPasswordBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt index e6260b6e7e..97fe93ad04 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt @@ -36,12 +36,14 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_bootstrap.* +import im.vector.app.databinding.BottomSheetBootstrapBinding +import im.vector.app.databinding.BottomSheetGenericListBinding +import kotlinx.parcelize.Parcelize + import javax.inject.Inject import kotlin.reflect.KClass -class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() { +class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() { @Parcelize data class Args( @@ -59,7 +61,9 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() { injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_bootstrap + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetBootstrapBinding { + return BottomSheetBootstrapBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -120,60 +124,60 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() { override fun invalidate() = withState(viewModel) { state -> when (state.step) { is BootstrapStep.CheckingMigration -> { - bootstrapIcon.isVisible = false - bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title) + views.bootstrapIcon.isVisible = false + views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title) showFragment(BootstrapWaitingFragment::class, Bundle()) } is BootstrapStep.FirstForm -> { - bootstrapIcon.isVisible = false - bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title) + views.bootstrapIcon.isVisible = false + views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title) showFragment(BootstrapSetupRecoveryKeyFragment::class, Bundle()) } is BootstrapStep.SetupPassphrase -> { - bootstrapIcon.isVisible = true - bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp)) - bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title) + views.bootstrapIcon.isVisible = true + views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp)) + views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title) showFragment(BootstrapEnterPassphraseFragment::class, Bundle()) } is BootstrapStep.ConfirmPassphrase -> { - bootstrapIcon.isVisible = true - bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp)) - bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title) + views.bootstrapIcon.isVisible = true + views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp)) + views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title) showFragment(BootstrapConfirmPassphraseFragment::class, Bundle()) } is BootstrapStep.AccountPassword -> { - bootstrapIcon.isVisible = true - bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user)) - bootstrapTitleText.text = getString(R.string.account_password) + views.bootstrapIcon.isVisible = true + views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user)) + views.bootstrapTitleText.text = getString(R.string.account_password) showFragment(BootstrapAccountPasswordFragment::class, Bundle()) } is BootstrapStep.Initializing -> { - bootstrapIcon.isVisible = true - bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp)) - bootstrapTitleText.text = getString(R.string.bootstrap_loading_title) + views.bootstrapIcon.isVisible = true + views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp)) + views.bootstrapTitleText.text = getString(R.string.bootstrap_loading_title) showFragment(BootstrapWaitingFragment::class, Bundle()) } is BootstrapStep.SaveRecoveryKey -> { - bootstrapIcon.isVisible = true - bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp)) - bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title) + views.bootstrapIcon.isVisible = true + views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp)) + views.bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title) showFragment(BootstrapSaveRecoveryKeyFragment::class, Bundle()) } is BootstrapStep.DoneSuccess -> { - bootstrapIcon.isVisible = true - bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp)) - bootstrapTitleText.text = getString(R.string.bootstrap_finish_title) + views.bootstrapIcon.isVisible = true + views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp)) + views.bootstrapTitleText.text = getString(R.string.bootstrap_finish_title) showFragment(BootstrapConclusionFragment::class, Bundle()) } is BootstrapStep.GetBackupSecretForMigration -> { val isKey = state.step.useKey() val drawableRes = if (isKey) R.drawable.ic_security_key_24dp else R.drawable.ic_security_phrase_24dp - bootstrapIcon.isVisible = true - bootstrapIcon.setImageDrawable(ContextCompat.getDrawable( + views.bootstrapIcon.isVisible = true + views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable( requireContext(), drawableRes) ) - bootstrapTitleText.text = getString(R.string.upgrade_security) + views.bootstrapTitleText.text = getString(R.string.upgrade_security) showFragment(BootstrapMigrateBackupFragment::class, Bundle()) } }.exhaustive diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt index a50d9e6dff..fcf20dcdcd 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConclusionFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.recover import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.text.toSpannable import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState @@ -25,27 +27,31 @@ import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.colorizeMatchingText -import kotlinx.android.synthetic.main.fragment_bootstrap_conclusion.* +import im.vector.app.databinding.FragmentBootstrapConclusionBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding + import javax.inject.Inject class BootstrapConclusionFragment @Inject constructor( private val colorProvider: ColorProvider -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_conclusion + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapConclusionBinding { + return FragmentBootstrapConclusionBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bootstrapConclusionContinue.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.Completed) } + views.bootstrapConclusionContinue.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.Completed) } } override fun invalidate() = withState(sharedViewModel) { state -> if (state.step !is BootstrapStep.DoneSuccess) return@withState - bootstrapConclusionText.text = getString( + views.bootstrapConclusionText.text = getString( R.string.bootstrap_cross_signing_success, getString(R.string.recovery_passphrase), getString(R.string.message_key) diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt index 46e9315477..ab3a87905f 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.recover import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.core.view.isGone import com.airbnb.mvrx.parentFragmentViewModel @@ -28,14 +30,19 @@ import im.vector.app.R import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding import io.reactivex.android.schedulers.AndroidSchedulers -import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.* + import java.util.concurrent.TimeUnit import javax.inject.Inject -class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragment() { +class BootstrapConfirmPassphraseFragment @Inject constructor() + : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding { + return FragmentBootstrapEnterPassphraseBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt index 53c3ee4356..2098bbb28f 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.recover import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState @@ -26,29 +28,34 @@ import com.jakewharton.rxbinding3.widget.textChanges import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding import im.vector.app.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 -class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragment() { +class BootstrapEnterPassphraseFragment @Inject constructor() + : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding { + return FragmentBootstrapEnterPassphraseBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice) - ssss_passphrase_enter_edittext.hint = getString(R.string.set_a_security_phrase_hint) + views.bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice) + views.ssssPassphraseEnterEdittext.hint = getString(R.string.set_a_security_phrase_hint) withState(sharedViewModel) { // set initial value (useful when coming back) - ssss_passphrase_enter_edittext.setText(it.passphrase ?: "") + views.ssssPassphraseEnterEdittext.setText(it.passphrase ?: "") } - ssss_passphrase_enter_edittext.editorActionEvents() + views.ssssPassphraseEnterEdittext.editorActionEvents() .throttleFirst(300, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe { @@ -58,7 +65,7 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen } .disposeOnDestroyView() - ssss_passphrase_enter_edittext.textChanges() + views.ssssPassphraseEnterEdittext.textChanges() .subscribe { // ssss_passphrase_enter_til.error = null sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: "")) @@ -74,8 +81,8 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen // } } - ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) } - bootstrapSubmit.debouncedClicks { submit() } + views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) } + views.bootstrapSubmit.debouncedClicks { submit() } } private fun submit() = withState(sharedViewModel) { state -> @@ -83,11 +90,11 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen return@withState } val score = state.passphraseStrength.invoke()?.score - val passphrase = ssss_passphrase_enter_edittext.text?.toString() + val passphrase = views.ssssPassphraseEnterEdittext.text?.toString() if (passphrase.isNullOrBlank()) { - ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message) + views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_empty_error_message) } else if (score != 4) { - ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_too_weak) + views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_passphrase_too_weak) } else { sharedViewModel.handle(BootstrapActions.GoToConfirmPassphrase(passphrase)) } @@ -96,21 +103,21 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen override fun invalidate() = withState(sharedViewModel) { state -> if (state.step is BootstrapStep.SetupPassphrase) { val isPasswordVisible = state.step.isPasswordVisible - ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false) - ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) + views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false) + views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) state.passphraseStrength.invoke()?.let { strength -> val score = strength.score - ssss_passphrase_security_progress.strength = score + views.ssssPassphraseSecurityProgress.strength = score if (score in 1..3) { val hint = strength.feedback?.getWarning(VectorLocale.applicationLocale)?.takeIf { it.isNotBlank() } ?: strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull() - if (hint != null && hint != ssss_passphrase_enter_til.error.toString()) { - ssss_passphrase_enter_til.error = hint + if (hint != null && hint != views.ssssPassphraseEnterTil.error.toString()) { + views.ssssPassphraseEnterTil.error = hint } } else { - ssss_passphrase_enter_til.error = null + views.ssssPassphraseEnterTil.error = null } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt index 0e3ba4c526..c45702d95a 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt @@ -21,7 +21,9 @@ import android.os.Bundle import android.text.InputType.TYPE_CLASS_TEXT import android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE import android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.core.text.toSpannable import androidx.core.view.isVisible @@ -37,9 +39,11 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.colorizeMatchingText import im.vector.app.core.utils.startImportTextFromFileIntent +import im.vector.app.databinding.FragmentBootstrapMigrateBackupBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding 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 org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.crypto.keysbackup.util.isValidRecoveryKey import java.util.concurrent.TimeUnit @@ -47,9 +51,11 @@ import javax.inject.Inject class BootstrapMigrateBackupFragment @Inject constructor( private val colorProvider: ColorProvider -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_migrate_backup + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapMigrateBackupBinding { + return FragmentBootstrapMigrateBackupBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt index e426394d77..7962233418 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSaveRecoveryKeyFragment.kt @@ -20,7 +20,9 @@ import android.app.Activity import android.content.ActivityNotFoundException import android.content.Intent import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isVisible import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState @@ -30,7 +32,9 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.core.utils.toast -import kotlinx.android.synthetic.main.fragment_bootstrap_save_key.* +import im.vector.app.databinding.FragmentBootstrapSaveKeyBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding + import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -38,18 +42,20 @@ import javax.inject.Inject class BootstrapSaveRecoveryKeyFragment @Inject constructor( private val colorProvider: ColorProvider -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_save_key + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSaveKeyBinding { + return FragmentBootstrapSaveKeyBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - recoverySave.clickableView.debouncedClicks { downloadRecoveryKey() } - recoveryCopy.clickableView.debouncedClicks { shareRecoveryKey() } - recoveryContinue.clickableView.debouncedClicks { + views.recoverySave.clickableView.debouncedClicks { downloadRecoveryKey() } + views.recoveryCopy.clickableView.debouncedClicks { shareRecoveryKey() } + views.recoveryContinue.clickableView.debouncedClicks { // We do not display the final Fragment anymore // TODO Do some cleanup // sharedViewModel.handle(BootstrapActions.GoToCompleted) @@ -112,7 +118,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor( val step = state.step if (step !is BootstrapStep.SaveRecoveryKey) return@withState - recoveryContinue.isVisible = step.isSaved - bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey() + views.recoveryContinue.isVisible = step.isSaved + views.bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey() } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt index ed68e3daac..23db24298e 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSetupRecoveryKeyFragment.kt @@ -17,18 +17,25 @@ package im.vector.app.features.crypto.recover import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isVisible import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_bootstrap_setup_recovery.* +import im.vector.app.databinding.FragmentBootstrapSetupRecoveryBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding + import javax.inject.Inject -class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragment() { +class BootstrapSetupRecoveryKeyFragment @Inject constructor() + : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_setup_recovery + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSetupRecoveryBinding { + return FragmentBootstrapSetupRecoveryBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() @@ -36,15 +43,15 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme super.onViewCreated(view, savedInstanceState) // Actions when a key backup exist - bootstrapSetupSecureSubmit.clickableView.debouncedClicks { + views.bootstrapSetupSecureSubmit.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.StartKeyBackupMigration) } // Actions when there is no key backup - bootstrapSetupSecureUseSecurityKey.clickableView.debouncedClicks { + views.bootstrapSetupSecureUseSecurityKey.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = false)) } - bootstrapSetupSecureUseSecurityPassphrase.clickableView.debouncedClicks { + views.bootstrapSetupSecureUseSecurityPassphrase.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = true)) } } @@ -53,23 +60,23 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme if (state.step is BootstrapStep.FirstForm) { if (state.step.keyBackUpExist) { // Display the set up action - bootstrapSetupSecureSubmit.isVisible = true - bootstrapSetupSecureUseSecurityKey.isVisible = false - bootstrapSetupSecureUseSecurityPassphrase.isVisible = false - bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false + views.bootstrapSetupSecureSubmit.isVisible = true + views.bootstrapSetupSecureUseSecurityKey.isVisible = false + views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = false + views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false } else { if (state.step.reset) { - bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title) - bootstrapSetupWarningTextView.isVisible = true + views.bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title) + views.bootstrapSetupWarningTextView.isVisible = true } else { - bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle) - bootstrapSetupWarningTextView.isVisible = false + views.bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle) + views.bootstrapSetupWarningTextView.isVisible = false } // Choose between create a passphrase or use a recovery key - bootstrapSetupSecureSubmit.isVisible = false - bootstrapSetupSecureUseSecurityKey.isVisible = true - bootstrapSetupSecureUseSecurityPassphrase.isVisible = true - bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true + views.bootstrapSetupSecureSubmit.isVisible = false + views.bootstrapSetupSecureUseSecurityKey.isVisible = true + views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = true + views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt index 0004420494..0e3eaa85d2 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapWaitingFragment.kt @@ -16,26 +16,33 @@ package im.vector.app.features.crypto.recover +import android.view.LayoutInflater +import android.view.ViewGroup import androidx.core.view.isVisible import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_bootstrap_waiting.* +import im.vector.app.databinding.FragmentBootstrapWaitingBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding + import javax.inject.Inject -class BootstrapWaitingFragment @Inject constructor() : VectorBaseFragment() { +class BootstrapWaitingFragment @Inject constructor() + : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_bootstrap_waiting + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapWaitingBinding { + return FragmentBootstrapWaitingBinding.inflate(inflater, container, false) + } val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() override fun invalidate() = withState(sharedViewModel) { state -> when (state.step) { is BootstrapStep.Initializing -> { - bootstrapLoadingStatusText.isVisible = true - bootstrapDescriptionText.isVisible = true - bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message + views.bootstrapLoadingStatusText.isVisible = true + views.bootstrapDescriptionText.isVisible = true + views.bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message } // is BootstrapStep.CheckingMigration -> { // bootstrapLoadingStatusText.isVisible = false @@ -43,8 +50,8 @@ class BootstrapWaitingFragment @Inject constructor() : VectorBaseFragment() { // } else -> { // just show the spinner - bootstrapLoadingStatusText.isVisible = false - bootstrapDescriptionText.isVisible = false + views.bootstrapLoadingStatusText.isVisible = false + views.bootstrapDescriptionText.isVisible = false } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt index a0ab1c86a7..6b6e94f043 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/QuadSLoadingFragment.kt @@ -16,10 +16,16 @@ package im.vector.app.features.crypto.verification +import android.view.LayoutInflater +import android.view.ViewGroup import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding +import im.vector.app.databinding.FragmentProgressBinding import javax.inject.Inject -class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_progress +class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment() { + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentProgressBinding { + return FragmentProgressBinding.inflate(inflater, container, false) + } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt index 6a9e89f4f5..53d55ed2ee 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt @@ -20,7 +20,9 @@ import android.app.Dialog import android.os.Bundle import android.os.Parcelable import android.view.KeyEvent +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.fragment.app.Fragment @@ -34,6 +36,8 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetVerificationBinding import im.vector.app.features.crypto.quads.SharedSecureStorageActivity import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment @@ -45,8 +49,8 @@ import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQrS import im.vector.app.features.crypto.verification.request.VerificationRequestFragment import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.settings.VectorSettingsActivity -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_verification.* +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME @@ -58,7 +62,7 @@ import timber.log.Timber import javax.inject.Inject import kotlin.reflect.KClass -class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { +class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { @Parcelize data class VerificationArgs( @@ -84,7 +88,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_verification + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationBinding { + return BottomSheetVerificationBinding.inflate(inflater, container, false) + } init { isCancelable = false @@ -115,7 +121,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { } VerificationBottomSheetViewEvents.GoToSettings -> { dismiss() - (activity as? VectorBaseActivity)?.navigator?.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY) + (activity as? VectorBaseActivity<*>)?.navigator?.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY) } }.exhaustive } @@ -152,27 +158,27 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { override fun invalidate() = withState(viewModel) { state -> state.otherUserMxItem?.let { matrixItem -> if (state.isMe) { - avatarRenderer.render(matrixItem, otherUserAvatarImageView) + avatarRenderer.render(matrixItem, views.otherUserAvatarImageView) if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified || state.verifiedFromPrivateKeys) { - otherUserShield.setImageResource(R.drawable.ic_shield_trusted) + views.otherUserShield.setImageResource(R.drawable.ic_shield_trusted) } else { - otherUserShield.setImageResource(R.drawable.ic_shield_warning) + views.otherUserShield.setImageResource(R.drawable.ic_shield_warning) } - otherUserNameText.text = getString( + views.otherUserNameText.text = getString( if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session ) - otherUserShield.isVisible = true + views.otherUserShield.isVisible = true } else { - avatarRenderer.render(matrixItem, otherUserAvatarImageView) + avatarRenderer.render(matrixItem, views.otherUserAvatarImageView) if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) { - otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName()) - otherUserShield.isVisible = true + views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName()) + views.otherUserShield.isVisible = true } else { - otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName()) - otherUserShield.isVisible = false + views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName()) + views.otherUserShield.isVisible = false } } } @@ -189,13 +195,13 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { } if (state.userThinkItsNotHim) { - otherUserNameText.text = getString(R.string.dialog_title_warning) + views.otherUserNameText.text = getString(R.string.dialog_title_warning) showFragment(VerificationNotMeFragment::class, Bundle()) return@withState } if (state.userWantsToCancel) { - otherUserNameText.text = getString(R.string.are_you_sure) + views.otherUserNameText.text = getString(R.string.are_you_sure) showFragment(VerificationCancelFragment::class, Bundle()) return@withState } @@ -287,7 +293,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() { // Transaction has not yet started if (state.pendingRequest.invoke()?.cancelConclusion != null) { // The request has been declined, we should dismiss - otherUserNameText.text = getString(R.string.verification_cancelled) + views.otherUserNameText.text = getString(R.string.verification_cancelled) showFragment(VerificationConclusionFragment::class, Bundle().apply { putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args( false, diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt index 8e31cd2fab..75f6afa1aa 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationCancelFragment.kt @@ -17,24 +17,31 @@ package im.vector.app.features.crypto.verification.cancel import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* + import javax.inject.Inject class VerificationCancelFragment @Inject constructor( val controller: VerificationCancelController -) : VectorBaseFragment(), VerificationCancelController.Listener { +) : VectorBaseFragment(), + VerificationCancelController.Listener { private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -42,13 +49,13 @@ class VerificationCancelFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() controller.listener = null super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt index 5059c2a2c9..7e5892ce67 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/cancel/VerificationNotMeFragment.kt @@ -17,24 +17,31 @@ package im.vector.app.features.crypto.verification.cancel import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding +import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* + import javax.inject.Inject class VerificationNotMeFragment @Inject constructor( val controller: VerificationNotMeController -) : VectorBaseFragment(), VerificationNotMeController.Listener { +) : VectorBaseFragment(), + VerificationNotMeController.Listener { private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -42,13 +49,13 @@ class VerificationNotMeFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() controller.listener = null super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt index 72cd063bbd..185fd85196 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.verification.choose import android.app.Activity import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState @@ -29,23 +31,27 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions 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.crypto.verification.VerificationBottomSheetViewModel import im.vector.app.features.qrcode.QrCodeScannerActivity -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* + import timber.log.Timber import javax.inject.Inject class VerificationChooseMethodFragment @Inject constructor( val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory, val controller: VerificationChooseMethodController -) : VectorBaseFragment(), VerificationChooseMethodController.Listener { +) : VectorBaseFragment(), + VerificationChooseMethodController.Listener { private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class) private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -54,13 +60,13 @@ class VerificationChooseMethodFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() controller.listener = null super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt index 885cc8f853..45e1617be1 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.crypto.verification.conclusion import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState @@ -25,15 +27,17 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding import im.vector.app.features.crypto.verification.VerificationAction import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* +import kotlinx.parcelize.Parcelize + import javax.inject.Inject class VerificationConclusionFragment @Inject constructor( val controller: VerificationConclusionController -) : VectorBaseFragment(), VerificationConclusionController.Listener { +) : VectorBaseFragment(), + VerificationConclusionController.Listener { @Parcelize data class Args( @@ -46,7 +50,9 @@ class VerificationConclusionFragment @Inject constructor( private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class) - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -55,13 +61,13 @@ class VerificationConclusionFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() controller.listener = null super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt index 20d0d7de75..27d5a8811a 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt @@ -16,7 +16,9 @@ package im.vector.app.features.crypto.verification.emoji import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState @@ -24,21 +26,25 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding import im.vector.app.features.crypto.verification.VerificationAction import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* + import javax.inject.Inject class VerificationEmojiCodeFragment @Inject constructor( val viewModelFactory: VerificationEmojiCodeViewModel.Factory, val controller: VerificationEmojiCodeController -) : VectorBaseFragment(), VerificationEmojiCodeController.Listener { +) : VectorBaseFragment(), + VerificationEmojiCodeController.Listener { private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class) private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -47,13 +53,13 @@ class VerificationEmojiCodeFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() controller.listener = null super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt index c2d7536134..0fdcb69d31 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt @@ -18,19 +18,22 @@ package im.vector.app.features.crypto.verification.qrconfirmation import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.MvRx import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding +import kotlinx.parcelize.Parcelize + import javax.inject.Inject class VerificationQRWaitingFragment @Inject constructor( val controller: VerificationQRWaitingController -) : VectorBaseFragment() { +) : VectorBaseFragment() { @Parcelize data class Args( @@ -38,7 +41,9 @@ class VerificationQRWaitingFragment @Inject constructor( val otherUserName: String ) : Parcelable - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -49,11 +54,11 @@ class VerificationQRWaitingFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt index 7e9b19e491..37ca016185 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQrScannedByOtherFragment.kt @@ -16,25 +16,31 @@ package im.vector.app.features.crypto.verification.qrconfirmation import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding import im.vector.app.features.crypto.verification.VerificationAction import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* + import javax.inject.Inject class VerificationQrScannedByOtherFragment @Inject constructor( val controller: VerificationQrScannedByOtherController -) : VectorBaseFragment(), VerificationQrScannedByOtherController.Listener { +) : VectorBaseFragment(), + VerificationQrScannedByOtherController.Listener { private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -46,13 +52,13 @@ class VerificationQrScannedByOtherFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() controller.listener = null super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt index fc7dcaf15f..40bcbc6c08 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/request/VerificationRequestFragment.kt @@ -16,25 +16,31 @@ package im.vector.app.features.crypto.verification.request import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding import im.vector.app.features.crypto.verification.VerificationAction import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel -import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* + import javax.inject.Inject class VerificationRequestFragment @Inject constructor( val controller: VerificationRequestController -) : VectorBaseFragment(), VerificationRequestController.Listener { +) : VectorBaseFragment(), + VerificationRequestController.Listener { private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class) - override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding { + return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -42,13 +48,13 @@ class VerificationRequestFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetVerificationRecyclerView.cleanup() + views.bottomSheetVerificationRecyclerView.cleanup() controller.listener = null super.onDestroyView() } private fun setupRecyclerView() { - bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt index 08bf2f12f0..917da224b1 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt @@ -17,8 +17,11 @@ package im.vector.app.features.discovery import android.app.Activity import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -30,9 +33,11 @@ import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.ensureProtocol +import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding import im.vector.app.features.discovery.change.SetIdentityServerFragment import im.vector.app.features.settings.VectorSettingsActivity -import kotlinx.android.synthetic.main.fragment_generic_recycler.* + import org.matrix.android.sdk.api.session.identity.SharedState import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.terms.TermsService @@ -41,9 +46,12 @@ import javax.inject.Inject class DiscoverySettingsFragment @Inject constructor( private val controller: DiscoverySettingsController, val viewModelFactory: DiscoverySettingsViewModel.Factory -) : VectorBaseFragment(), DiscoverySettingsController.Listener { +) : VectorBaseFragment(), + DiscoverySettingsController.Listener { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel by fragmentViewModel(DiscoverySettingsViewModel::class) @@ -55,7 +63,7 @@ class DiscoverySettingsFragment @Inject constructor( sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java) controller.listener = this - genericRecyclerView.configureWith(controller) + views.genericRecyclerView.configureWith(controller) sharedViewModel.navigateEvent.observeEvent(this) { when (it) { @@ -74,7 +82,7 @@ class DiscoverySettingsFragment @Inject constructor( } override fun onDestroyView() { - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() controller.listener = null super.onDestroyView() } @@ -85,7 +93,7 @@ class DiscoverySettingsFragment @Inject constructor( override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_discovery_category) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_discovery_category) // If some 3pids are pending, we can try to check if they have been verified here viewModel.handle(DiscoverySettingsAction.Refresh) diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt index 8fb4fc4156..e26e85b23d 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.discovery.change import android.app.Activity import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.appcompat.app.AlertDialog import androidx.core.text.toSpannable @@ -33,17 +35,21 @@ import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.colorizeMatchingText +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentSetIdentityServerBinding import im.vector.app.features.discovery.DiscoverySharedViewModel -import kotlinx.android.synthetic.main.fragment_set_identity_server.* + import org.matrix.android.sdk.api.session.terms.TermsService import javax.inject.Inject class SetIdentityServerFragment @Inject constructor( val viewModelFactory: SetIdentityServerViewModel.Factory, val colorProvider: ColorProvider -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_set_identity_server + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSetIdentityServerBinding { + return FragmentSetIdentityServerBinding.inflate(inflater, container, false) + } private val viewModel by fragmentViewModel(SetIdentityServerViewModel::class) @@ -147,7 +153,7 @@ class SetIdentityServerFragment @Inject constructor( override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.identity_server) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.identity_server) } private val termsActivityResultLauncher = registerStartForActivityResult { diff --git a/vector/src/main/java/im/vector/app/features/grouplist/GroupListFragment.kt b/vector/src/main/java/im/vector/app/features/grouplist/GroupListFragment.kt index d4ba4f3150..0b800c0524 100644 --- a/vector/src/main/java/im/vector/app/features/grouplist/GroupListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/grouplist/GroupListFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.grouplist import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Success import com.airbnb.mvrx.fragmentViewModel @@ -29,28 +31,33 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentGroupListBinding import im.vector.app.features.home.HomeActivitySharedAction import im.vector.app.features.home.HomeSharedActionViewModel -import kotlinx.android.synthetic.main.fragment_group_list.* + import org.matrix.android.sdk.api.session.group.model.GroupSummary import javax.inject.Inject class GroupListFragment @Inject constructor( val groupListViewModelFactory: GroupListViewModel.Factory, private val groupController: GroupSummaryController -) : VectorBaseFragment(), GroupSummaryController.Callback { +) : VectorBaseFragment(), + GroupSummaryController.Callback { private lateinit var sharedActionViewModel: HomeSharedActionViewModel private val viewModel: GroupListViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_group_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGroupListBinding { + return FragmentGroupListBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java) groupController.callback = this - stateView.contentView = groupListView - groupListView.configureWith(groupController) + views.stateView.contentView = views.groupListView + views.groupListView.configureWith(groupController) viewModel.observeViewEvents { when (it) { is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup) @@ -60,14 +67,14 @@ class GroupListFragment @Inject constructor( override fun onDestroyView() { groupController.callback = null - groupListView.cleanup() + views.groupListView.cleanup() super.onDestroyView() } override fun invalidate() = withState(viewModel) { state -> when (state.asyncGroups) { - is Incomplete -> stateView.state = StateView.State.Loading - is Success -> stateView.state = StateView.State.Content + is Incomplete -> views.stateView.state = StateView.State.Loading + is Success -> views.stateView.state = StateView.State.Content } groupController.update(state) } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index d4aff21c40..8b4c462a5a 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -21,8 +21,10 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.MenuItem import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.core.view.GravityCompat @@ -40,6 +42,7 @@ import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.pushers.PushersManager import im.vector.app.core.utils.toast +import im.vector.app.databinding.ActivityHomeBinding import im.vector.app.features.disclaimer.showDisclaimerDialog import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.notifications.NotificationDrawerManager @@ -56,9 +59,9 @@ import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import im.vector.app.features.workers.signout.ServerBackupStatusViewState import im.vector.app.push.fcm.FcmHelper import io.reactivex.android.schedulers.AndroidSchedulers -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.activity_home.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import kotlinx.parcelize.Parcelize + + import org.matrix.android.sdk.api.session.InitialSyncProgressService import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.util.MatrixItem @@ -71,7 +74,11 @@ data class HomeActivityArgs( val accountCreation: Boolean ) : Parcelable -class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory, +class HomeActivity : + VectorBaseActivity(), + ToolbarConfigurable, + UnknownDeviceDetectorSharedViewModel.Factory, + ServerBackupStatusViewModel.Factory, NavigationInterceptor { private lateinit var sharedActionViewModel: HomeSharedActionViewModel @@ -98,7 +105,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet } } - override fun getLayoutRes() = R.layout.activity_home + override fun getBinding() = ActivityHomeBinding.inflate(layoutInflater) override fun injectWith(injector: ScreenComponent) { injector.inject(this) @@ -116,7 +123,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet super.onCreate(savedInstanceState) FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice()) sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java) - drawerLayout.addDrawerListener(drawerListener) + views.drawerLayout.addDrawerListener(drawerListener) if (isFirstCreation()) { replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java) replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java) @@ -126,10 +133,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet .observe() .subscribe { sharedAction -> when (sharedAction) { - is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START) - is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START) + is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START) + is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START) is HomeActivitySharedAction.OpenGroup -> { - drawerLayout.closeDrawer(GravityCompat.START) + views.drawerLayout.closeDrawer(GravityCompat.START) replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true) } }.exhaustive @@ -197,24 +204,24 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet private fun renderState(state: HomeActivityViewState) { when (val status = state.initialSyncProgressServiceStatus) { is InitialSyncProgressService.Status.Idle -> { - waiting_view.isVisible = false + views.waitingView.root.isVisible = false } is InitialSyncProgressService.Status.Progressing -> { Timber.v("${getString(status.statusText)} ${status.percentProgress}") - waiting_view.setOnClickListener { + views.waitingView.root.setOnClickListener { // block interactions } - waitingHorizontalProgress.apply { + views.waitingView.waitingHorizontalProgress.apply { isIndeterminate = false max = 100 progress = status.percentProgress isVisible = true } - waitingStatusText.apply { + views.waitingView.waitingStatusText.apply { text = getString(status.statusText) isVisible = true } - waiting_view.isVisible = true + views.waitingView.root.isVisible = true } }.exhaustive } @@ -269,7 +276,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet ).apply { colorInt = ThemeUtils.getColor(this@HomeActivity, R.attr.vctr_notice_secondary) contentAction = Runnable { - (weakCurrentActivity?.get() as? VectorBaseActivity)?.let { + (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { // action(it) homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed) it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS) @@ -282,7 +289,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed) }, true) addButton(getString(R.string.settings), Runnable { - (weakCurrentActivity?.get() as? VectorBaseActivity)?.let { + (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { // action(it) homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed) it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS) @@ -292,7 +299,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet ) } - private fun promptSecurityEvent(userItem: MatrixItem.UserItem?, titleRes: Int, descRes: Int, action: ((VectorBaseActivity) -> Unit)) { + private fun promptSecurityEvent(userItem: MatrixItem.UserItem?, titleRes: Int, descRes: Int, action: ((VectorBaseActivity<*>) -> Unit)) { popupAlertManager.postVectorAlert( VerificationVectorAlert( uid = "upgradeSecurity", @@ -303,7 +310,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet ).apply { colorInt = ContextCompat.getColor(this@HomeActivity, R.color.riotx_positive_accent) contentAction = Runnable { - (weakCurrentActivity?.get() as? VectorBaseActivity)?.let { + (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { action(it) } } @@ -321,7 +328,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet } override fun onDestroy() { - drawerLayout.removeDrawerListener(drawerListener) + views.drawerLayout.removeDrawerListener(drawerListener) super.onDestroy() } @@ -375,8 +382,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet } override fun onBackPressed() { - if (drawerLayout.isDrawerOpen(GravityCompat.START)) { - drawerLayout.closeDrawer(GravityCompat.START) + if (views.drawerLayout.isDrawerOpen(GravityCompat.START)) { + views.drawerLayout.closeDrawer(GravityCompat.START) } else { super.onBackPressed() } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 1c63d63ae0..ff5dcb9156 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.home import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import com.airbnb.mvrx.activityViewModel @@ -33,6 +35,8 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.ui.views.ActiveCallView import im.vector.app.core.ui.views.ActiveCallViewHolder import im.vector.app.core.ui.views.KeysBackupBanner +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentHomeDetailBinding import im.vector.app.features.call.SharedActiveCallViewModel import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.WebRtcPeerConnectionManager @@ -46,7 +50,7 @@ import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.workers.signout.BannerState import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import im.vector.app.features.workers.signout.ServerBackupStatusViewState -import kotlinx.android.synthetic.main.fragment_home_detail.* + import org.matrix.android.sdk.api.session.group.model.GroupSummary import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo @@ -64,7 +68,10 @@ class HomeDetailFragment @Inject constructor( private val alertManager: PopupAlertManager, private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager, private val vectorPreferences: VectorPreferences -) : VectorBaseFragment(), KeysBackupBanner.Delegate, ActiveCallView.Callback, ServerBackupStatusViewModel.Factory { +) : VectorBaseFragment(), + KeysBackupBanner.Delegate, + ActiveCallView.Callback, + ServerBackupStatusViewModel.Factory { private val viewModel: HomeDetailViewModel by fragmentViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel() @@ -73,7 +80,9 @@ class HomeDetailFragment @Inject constructor( private lateinit var sharedActionViewModel: HomeSharedActionViewModel private lateinit var sharedCallActionViewModel: SharedActiveCallViewModel - override fun getLayoutResId() = R.layout.fragment_home_detail + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeDetailBinding { + return FragmentHomeDetailBinding.inflate(inflater, container, false) + } private val activeCallViewHolder = ActiveCallViewHolder() @@ -89,7 +98,7 @@ class HomeDetailFragment @Inject constructor( withState(viewModel) { // Update the navigation view if needed (for when we restore the tabs) - bottomNavigationView.selectedItemId = it.displayMode.toMenuId() + views.bottomNavigationView.selectedItemId = it.displayMode.toMenuId() } viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary -> @@ -132,8 +141,8 @@ class HomeDetailFragment @Inject constructor( } private fun checkNotificationTabStatus() { - val wasVisible = bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible - bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab() + val wasVisible = views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible + views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab() if (wasVisible && !vectorPreferences.labAddNotificationTab()) { // As we hide it check if it's not the current item! withState(viewModel) { @@ -156,7 +165,7 @@ class HomeDetailFragment @Inject constructor( ).apply { colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent) contentAction = Runnable { - (weakCurrentActivity?.get() as? VectorBaseActivity) + (weakCurrentActivity?.get() as? VectorBaseActivity<*>) ?.navigator ?.requestSessionVerification(requireContext(), newest.deviceId ?: "") unknownDeviceDetectorSharedViewModel.handle( @@ -184,7 +193,7 @@ class HomeDetailFragment @Inject constructor( ).apply { colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent) contentAction = Runnable { - (weakCurrentActivity?.get() as? VectorBaseActivity)?.let { + (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { // mark as ignored to avoid showing it again unknownDeviceDetectorSharedViewModel.handle( UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(oldUnverified.mapNotNull { it.deviceId }) @@ -204,7 +213,7 @@ class HomeDetailFragment @Inject constructor( private fun onGroupChange(groupSummary: GroupSummary?) { groupSummary?.let { // Use GlideApp with activity context to avoid the glideRequests to be paused - avatarRenderer.render(it.toMatrixItem(), groupToolbarAvatarImageView, GlideApp.with(requireActivity())) + avatarRenderer.render(it.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity())) } } @@ -212,20 +221,20 @@ class HomeDetailFragment @Inject constructor( serverBackupStatusViewModel .subscribe(this) { when (val banState = it.bannerState.invoke()) { - is BannerState.Setup -> homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false) - BannerState.BackingUp -> homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false) + is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false) + BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false) null, - BannerState.Hidden -> homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false) + BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false) } } - homeKeysBackupBanner.delegate = this + views.homeKeysBackupBanner.delegate = this } private fun setupActiveCallView() { activeCallViewHolder.bind( - activeCallPiP, - activeCallView, - activeCallPiPWrap, + views.activeCallPiP, + views.activeCallView, + views.activeCallPiPWrap, this ) } @@ -233,17 +242,17 @@ class HomeDetailFragment @Inject constructor( private fun setupToolbar() { val parentActivity = vectorBaseActivity if (parentActivity is ToolbarConfigurable) { - parentActivity.configure(groupToolbar) + parentActivity.configure(views.groupToolbar) } - groupToolbar.title = "" - groupToolbarAvatarImageView.debouncedClicks { + views.groupToolbar.title = "" + views.groupToolbarAvatarImageView.debouncedClicks { sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer) } } private fun setupBottomNavigationView() { - bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab() - bottomNavigationView.setOnNavigationItemSelectedListener { + views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab() + views.bottomNavigationView.setOnNavigationItemSelectedListener { val displayMode = when (it.itemId) { R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS @@ -266,7 +275,7 @@ class HomeDetailFragment @Inject constructor( } private fun switchDisplayMode(displayMode: RoomListDisplayMode) { - groupToolbarTitleView.setText(displayMode.titleRes) + views.groupToolbarTitleView.setText(displayMode.titleRes) updateSelectedFragment(displayMode) } @@ -302,10 +311,10 @@ class HomeDetailFragment @Inject constructor( override fun invalidate() = withState(viewModel) { Timber.v(it.toString()) - bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople) - bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms) - bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup) - syncStateView.render(it.syncState) + views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople) + views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms) + views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup) + views.syncStateView.render(it.syncState) } private fun BadgeDrawable.render(count: Int, highlight: Boolean) { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt index 1a60d8e219..5271c0101f 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.home import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.app.ActivityOptionsCompat import androidx.core.view.ViewCompat import androidx.core.view.isVisible @@ -27,12 +29,14 @@ import im.vector.app.core.extensions.observeK import im.vector.app.core.extensions.replaceChildFragment import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.startSharePlainTextIntent +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentHomeDrawerBinding import im.vector.app.features.grouplist.GroupListFragment import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorSettingsActivity import im.vector.app.features.usercode.UserCodeActivity import im.vector.app.features.workers.signout.SignOutUiWorker -import kotlinx.android.synthetic.main.fragment_home_drawer.* + import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject @@ -41,11 +45,13 @@ class HomeDrawerFragment @Inject constructor( private val session: Session, private val vectorPreferences: VectorPreferences, private val avatarRenderer: AvatarRenderer -) : VectorBaseFragment() { +) : VectorBaseFragment() { private lateinit var sharedActionViewModel: HomeSharedActionViewModel - override fun getLayoutResId() = R.layout.fragment_home_drawer + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeDrawerBinding { + return FragmentHomeDrawerBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -58,40 +64,40 @@ class HomeDrawerFragment @Inject constructor( session.getUserLive(session.myUserId).observeK(viewLifecycleOwner) { optionalUser -> val user = optionalUser?.getOrNull() if (user != null) { - avatarRenderer.render(user.toMatrixItem(), homeDrawerHeaderAvatarView) - homeDrawerUsernameView.text = user.displayName - homeDrawerUserIdView.text = user.userId + avatarRenderer.render(user.toMatrixItem(), views.homeDrawerHeaderAvatarView) + views.homeDrawerUsernameView.text = user.displayName + views.homeDrawerUserIdView.text = user.userId } } // Profile - homeDrawerHeader.debouncedClicks { + views.homeDrawerHeader.debouncedClicks { sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) navigator.openSettings(requireActivity(), directAccess = VectorSettingsActivity.EXTRA_DIRECT_ACCESS_GENERAL) } // Settings - homeDrawerHeaderSettingsView.debouncedClicks { + views.homeDrawerHeaderSettingsView.debouncedClicks { sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) navigator.openSettings(requireActivity()) } // Sign out - homeDrawerHeaderSignoutView.debouncedClicks { + views.homeDrawerHeaderSignoutView.debouncedClicks { sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) SignOutUiWorker(requireActivity()).perform() } - homeDrawerQRCodeButton.debouncedClicks { + views.homeDrawerQRCodeButton.debouncedClicks { UserCodeActivity.newIntent(requireContext(), sharedActionViewModel.session.myUserId).let { val options = ActivityOptionsCompat.makeSceneTransitionAnimation( requireActivity(), - homeDrawerHeaderAvatarView, - ViewCompat.getTransitionName(homeDrawerHeaderAvatarView) ?: "" + views.homeDrawerHeaderAvatarView, + ViewCompat.getTransitionName(views.homeDrawerHeaderAvatarView) ?: "" ) startActivity(it, options.toBundle()) } } - homeDrawerInviteFriendButton.debouncedClicks { + views.homeDrawerInviteFriendButton.debouncedClicks { session.permalinkService().createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink -> val text = getString(R.string.invite_friends_text, permalink) @@ -106,8 +112,8 @@ class HomeDrawerFragment @Inject constructor( } // Debug menu - homeDrawerHeaderDebugView.isVisible = BuildConfig.DEBUG && vectorPreferences.developerMode() - homeDrawerHeaderDebugView.debouncedClicks { + views.homeDrawerHeaderDebugView.isVisible = BuildConfig.DEBUG && vectorPreferences.developerMode() + views.homeDrawerHeaderDebugView.debouncedClicks { sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) navigator.openDebug(requireActivity()) } diff --git a/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt b/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt index e56887b85f..a5c9f1ad6a 100644 --- a/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/LoadingFragment.kt @@ -18,20 +18,26 @@ package im.vector.app.features.home import android.graphics.drawable.AnimationDrawable import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_loading.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoadingBinding + import javax.inject.Inject -class LoadingFragment @Inject constructor() : VectorBaseFragment() { +class LoadingFragment @Inject constructor() : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_loading + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoadingBinding { + return FragmentLoadingBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val background = animatedLogoImageView.background + val background = views.animatedLogoImageView.background if (background is AnimationDrawable) { background.start() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt index c147985809..de78afdaa8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt @@ -17,27 +17,34 @@ package im.vector.app.features.home.room.breadcrumbs import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentBreadcrumbsBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding import im.vector.app.features.home.room.detail.RoomDetailSharedAction import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel -import kotlinx.android.synthetic.main.fragment_breadcrumbs.* + import javax.inject.Inject class BreadcrumbsFragment @Inject constructor( private val breadcrumbsController: BreadcrumbsController, val breadcrumbsViewModelFactory: BreadcrumbsViewModel.Factory -) : VectorBaseFragment(), BreadcrumbsController.Listener { +) : VectorBaseFragment(), + BreadcrumbsController.Listener { private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel private val breadcrumbsViewModel: BreadcrumbsViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_breadcrumbs + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBreadcrumbsBinding { + return FragmentBreadcrumbsBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -46,13 +53,13 @@ class BreadcrumbsFragment @Inject constructor( } override fun onDestroyView() { - breadcrumbsRecyclerView.cleanup() + views.breadcrumbsRecyclerView.cleanup() breadcrumbsController.listener = null super.onDestroyView() } private fun setupRecyclerView() { - breadcrumbsRecyclerView.configureWith(breadcrumbsController, BreadcrumbsAnimator(), hasFixedSize = false) + views.breadcrumbsRecyclerView.configureWith(breadcrumbsController, BreadcrumbsAnimator(), hasFixedSize = false) breadcrumbsController.listener = this } @@ -67,6 +74,6 @@ class BreadcrumbsFragment @Inject constructor( } fun scrollToTop() { - breadcrumbsRecyclerView.scrollToPosition(0) + views.breadcrumbsRecyclerView.scrollToPosition(0) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt index de82689303..9c2d5bafee 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt @@ -37,8 +37,8 @@ import im.vector.app.features.room.RequireActiveMembershipViewModel import im.vector.app.features.room.RequireActiveMembershipViewState import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewModel import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewState -import kotlinx.android.synthetic.main.activity_room_detail.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* + + import javax.inject.Inject class RoomDetailActivity : diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 1a7a7ec359..03db33d5ac 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -167,10 +167,10 @@ import im.vector.app.features.widgets.WidgetKind import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_room_detail.* -import kotlinx.android.synthetic.main.composer_layout.view.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import kotlinx.parcelize.Parcelize + + + import nl.dionsegijn.konfetti.models.Shape import nl.dionsegijn.konfetti.models.Size import org.billcarsonfr.jsonviewer.JSonViewerDialog diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt index d48d994caa..427f30fc01 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt @@ -31,7 +31,7 @@ import androidx.transition.Transition import androidx.transition.TransitionManager import androidx.transition.TransitionSet import im.vector.app.R -import kotlinx.android.synthetic.main.composer_layout.view.* + import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel /** diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt index bf3ee97f9e..52c9dbae00 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt @@ -18,7 +18,9 @@ package im.vector.app.features.home.room.detail.readreceipts import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.args import im.vector.app.R @@ -26,11 +28,13 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding import im.vector.app.features.home.room.detail.timeline.action.EventSharedAction import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.* +import kotlinx.parcelize.Parcelize + import javax.inject.Inject @Parcelize @@ -41,7 +45,9 @@ data class DisplayReadReceiptArgs( /** * Bottom sheet displaying list of read receipts for a given event ordered by descending timestamp */ -class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), DisplayReadReceiptsController.Listener { +class DisplayReadReceiptsBottomSheet : + VectorBaseBottomSheetDialogFragment(), + DisplayReadReceiptsController.Listener { @Inject lateinit var epoxyController: DisplayReadReceiptsController @@ -53,19 +59,21 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), Di injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding { + return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) - bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false) - bottomSheetTitle.text = getString(R.string.seen_by) + views.bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false) + views.bottomSheetTitle.text = getString(R.string.seen_by) epoxyController.listener = this epoxyController.setData(displayReadReceiptArgs.readReceipts) } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() epoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt index f85dccbb27..8ee376702b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt @@ -19,22 +19,23 @@ package im.vector.app.features.home.room.detail.search import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.LayoutInflater import androidx.appcompat.widget.SearchView import com.airbnb.mvrx.MvRx import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity -import kotlinx.android.synthetic.main.activity_search.* +import im.vector.app.databinding.ActivitySearchBinding -class SearchActivity : VectorBaseActivity() { +class SearchActivity : VectorBaseActivity() { private val searchFragment: SearchFragment? get() { return supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as? SearchFragment } - override fun getLayoutRes() = R.layout.activity_search + override fun getBinding() = ActivitySearchBinding.inflate(layoutInflater) override fun injectWith(injector: ScreenComponent) { super.injectWith(injector) @@ -43,7 +44,7 @@ class SearchActivity : VectorBaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - configureToolbar(searchToolbar) + configureToolbar(views.searchToolbar) } override fun initUiAndData() { @@ -51,7 +52,7 @@ class SearchActivity : VectorBaseActivity() { val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return addFragment(R.id.searchFragmentContainer, SearchFragment::class.java, fragmentArgs, FRAGMENT_TAG) } - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + views.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { searchFragment?.search(query) return true @@ -62,7 +63,7 @@ class SearchActivity : VectorBaseActivity() { } }) // Open the keyboard immediately - searchView.requestFocus() + views.searchView.requestFocus() } companion object { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt index 201e9a4f82..47faf72a25 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.home.room.detail.search import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.LinearLayoutManager import com.airbnb.mvrx.Fail @@ -34,8 +36,10 @@ import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_search.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentSearchBinding +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.session.events.model.Event import javax.inject.Inject @@ -47,32 +51,36 @@ data class SearchArgs( class SearchFragment @Inject constructor( val viewModelFactory: SearchViewModel.Factory, private val controller: SearchResultController -) : VectorBaseFragment(), StateView.EventCallback, SearchResultController.Listener { +) : VectorBaseFragment(), + StateView.EventCallback, + SearchResultController.Listener { private val fragmentArgs: SearchArgs by args() private val searchViewModel: SearchViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_search + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSearchBinding { + return FragmentSearchBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - stateView.contentView = searchResultRecycler - stateView.eventCallback = this + views.stateView.contentView = views.searchResultRecycler + views.stateView.eventCallback = this configureRecyclerView() } private fun configureRecyclerView() { - searchResultRecycler.trackItemsVisibilityChange() - searchResultRecycler.configureWith(controller, showDivider = false) - (searchResultRecycler.layoutManager as? LinearLayoutManager)?.stackFromEnd = true + views.searchResultRecycler.trackItemsVisibilityChange() + views.searchResultRecycler.configureWith(controller, showDivider = false) + (views.searchResultRecycler.layoutManager as? LinearLayoutManager)?.stackFromEnd = true controller.listener = this } override fun onDestroy() { super.onDestroy() - searchResultRecycler?.cleanup() + views.searchResultRecycler?.cleanup() controller.listener = null } @@ -80,20 +88,20 @@ class SearchFragment @Inject constructor( if (state.searchResult.isNullOrEmpty()) { when (state.asyncSearchRequest) { is Loading -> { - stateView.state = StateView.State.Loading + views.stateView.state = StateView.State.Loading } is Fail -> { - stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error)) + views.stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error)) } is Success -> { - stateView.state = StateView.State.Empty( + views.stateView.state = StateView.State.Empty( title = getString(R.string.search_no_results), image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search_no_results)) } } } else { controller.setData(state) - stateView.state = StateView.State.Content + views.stateView.state = StateView.State.Content } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt index 81e9ffd24e..0b6df89989 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt @@ -16,7 +16,9 @@ package im.vector.app.features.home.room.detail.timeline.action import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -24,14 +26,17 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData -import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* + import javax.inject.Inject /** * Bottom sheet fragment that shows a message preview with list of contextual actions */ -class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), MessageActionsEpoxyController.MessageActionsEpoxyControllerListener { +class MessageActionsBottomSheet : + VectorBaseBottomSheetDialogFragment(), + MessageActionsEpoxyController.MessageActionsEpoxyControllerListener { @Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory @Inject lateinit var messageActionsEpoxyController: MessageActionsEpoxyController @@ -46,17 +51,19 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding { + return BottomSheetGenericListBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) - bottomSheetRecyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetRecyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true) messageActionsEpoxyController.listener = this } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() super.onDestroyView() } @@ -76,8 +83,8 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message if (eventAction is EventSharedAction.ReportContent) { // Toggle report menu // Enable item animation - if (bottomSheetRecyclerView.itemAnimator == null) { - bottomSheetRecyclerView.itemAnimator = MessageActionsAnimator() + if (views.bottomSheetRecyclerView.itemAnimator == null) { + views.bottomSheetRecyclerView.itemAnimator = MessageActionsAnimator() } viewModel.handle(MessageActionsAction.ToggleReportMenu) } else { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/TimelineEventFragmentArgs.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/TimelineEventFragmentArgs.kt index fcfd6cdb8d..1bb1a876bd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/TimelineEventFragmentArgs.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/TimelineEventFragmentArgs.kt @@ -18,7 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.action import android.os.Parcelable import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize @Parcelize data class TimelineEventFragmentArgs( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt index 7a6bb412cc..376da4c650 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt @@ -16,7 +16,9 @@ package im.vector.app.features.home.room.detail.timeline.edithistory import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -25,16 +27,19 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData import im.vector.app.features.html.EventHtmlRenderer -import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.* + import javax.inject.Inject /** * Bottom sheet displaying list of edits for a given event ordered by timestamp */ -class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() { +class ViewEditHistoryBottomSheet : + VectorBaseBottomSheetDialogFragment() { private val viewModel: ViewEditHistoryViewModel by fragmentViewModel(ViewEditHistoryViewModel::class) @@ -49,19 +54,21 @@ class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() { injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding { + return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bottomSheetRecyclerView.configureWith( + views.bottomSheetRecyclerView.configureWith( epoxyController, showDivider = true, hasFixedSize = false) - bottomSheetTitle.text = context?.getString(R.string.message_edits) + views.bottomSheetTitle.text = context?.getString(R.string.message_edits) } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt index b0fc293fda..38575f0cc9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.detail.timeline.item import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.internal.session.room.VerificationState diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt index be368682c1..d004d5b3c6 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/PollResultLineView.kt @@ -23,7 +23,7 @@ import android.widget.LinearLayout import androidx.core.content.withStyledAttributes import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide -import kotlinx.android.synthetic.main.item_timeline_event_poll_result_item.view.* + class PollResultLineView @JvmOverloads constructor( context: Context, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt index c1d71f4162..5cc4108e10 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt @@ -17,7 +17,9 @@ package im.vector.app.features.home.room.detail.timeline.reactions import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -26,17 +28,21 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding import im.vector.app.features.home.room.detail.timeline.action.EventSharedAction import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData -import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.* + import javax.inject.Inject /** * Bottom sheet displaying list of reactions for a given event ordered by timestamp */ -class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReactionsEpoxyController.Listener { +class ViewReactionsBottomSheet : + VectorBaseBottomSheetDialogFragment(), + ViewReactionsEpoxyController.Listener { private val viewModel: ViewReactionsViewModel by fragmentViewModel(ViewReactionsViewModel::class) @@ -49,18 +55,20 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReac injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding { + return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) - bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false, showDivider = true) - bottomSheetTitle.text = context?.getString(R.string.reactions) + views.bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false, showDivider = true) + views.bottomSheetTitle.text = context?.getString(R.string.reactions) epoxyController.listener = this } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() epoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt index c69e47614c..01745e3f05 100755 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt @@ -25,7 +25,7 @@ import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.media.ImageContentRenderer -import kotlinx.android.synthetic.main.url_preview.view.* + import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.media.PreviewUrlData diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBannerView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBannerView.kt index 7fe8b87fe0..f0289cedfa 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBannerView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBannerView.kt @@ -21,7 +21,7 @@ import android.util.AttributeSet import android.view.View import android.widget.RelativeLayout import im.vector.app.R -import kotlinx.android.synthetic.main.view_room_widgets_banner.view.* + import org.matrix.android.sdk.api.session.widgets.model.Widget class RoomWidgetsBannerView @JvmOverloads constructor( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt index 1799deae66..2bdde63beb 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt @@ -17,7 +17,9 @@ package im.vector.app.features.home.room.detail.widget import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -26,18 +28,22 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.core.resources.ColorProvider +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding import im.vector.app.features.home.room.detail.RoomDetailAction import im.vector.app.features.home.room.detail.RoomDetailViewModel import im.vector.app.features.home.room.detail.RoomDetailViewState import im.vector.app.features.navigation.Navigator -import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.* + import org.matrix.android.sdk.api.session.widgets.model.Widget import javax.inject.Inject /** * Bottom sheet displaying active widgets in a room */ -class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidgetsController.Listener { +class RoomWidgetsBottomSheet : + VectorBaseBottomSheetDialogFragment(), + RoomWidgetsController.Listener { @Inject lateinit var epoxyController: RoomWidgetsController @Inject lateinit var colorProvider: ColorProvider @@ -49,14 +55,16 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding { + return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false) - bottomSheetTitle.text = getString(R.string.active_widgets_title) - bottomSheetTitle.textSize = 20f - bottomSheetTitle.setTextColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)) + views.bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false) + views.bottomSheetTitle.text = getString(R.string.active_widgets_title) + views.bottomSheetTitle.textSize = 20f + views.bottomSheetTitle.setTextColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)) epoxyController.listener = this roomDetailViewModel.asyncSubscribe(this, RoomDetailViewState::activeRoomWidgets) { epoxyController.setData(it) @@ -64,7 +72,7 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() epoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt index ee33b4339c..4158256a76 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt @@ -19,24 +19,26 @@ package im.vector.app.features.home.room.filtered import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.LayoutInflater import androidx.appcompat.widget.SearchView import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivityFilteredRoomsBinding import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.room.list.RoomListFragment import im.vector.app.features.home.room.list.RoomListParams -import kotlinx.android.synthetic.main.activity_filtered_rooms.* -class FilteredRoomsActivity : VectorBaseActivity() { + +class FilteredRoomsActivity : VectorBaseActivity() { private val roomListFragment: RoomListFragment? get() { return supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as? RoomListFragment } - override fun getLayoutRes() = R.layout.activity_filtered_rooms + override fun getBinding() = ActivityFilteredRoomsBinding.inflate(layoutInflater) override fun injectWith(injector: ScreenComponent) { injector.inject(this) @@ -44,12 +46,12 @@ class FilteredRoomsActivity : VectorBaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - configureToolbar(filteredRoomsToolbar) + configureToolbar(views.filteredRoomsToolbar) if (isFirstCreation()) { val params = RoomListParams(RoomListDisplayMode.FILTERED) replaceFragment(R.id.filteredRoomsFragmentContainer, RoomListFragment::class.java, params, FRAGMENT_TAG) } - filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + views.filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { return true } @@ -60,7 +62,7 @@ class FilteredRoomsActivity : VectorBaseActivity() { } }) // Open the keyboard immediately - filteredRoomsSearchView.requestFocus() + views.filteredRoomsSearchView.requestFocus() } companion object { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index b4f525c119..300b38ee17 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -18,9 +18,11 @@ package im.vector.app.features.home.room.list import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.core.view.isVisible @@ -40,6 +42,8 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentRoomListBinding import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet @@ -47,8 +51,8 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.home.room.list.widget.NotifsFabMenuView import im.vector.app.features.notifications.NotificationDrawerManager -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_room_list.* +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -66,7 +70,10 @@ class RoomListFragment @Inject constructor( val roomListViewModelFactory: RoomListViewModel.Factory, private val notificationDrawerManager: NotificationDrawerManager, private val sharedViewPool: RecyclerView.RecycledViewPool -) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, NotifsFabMenuView.Listener { +) : VectorBaseFragment(), + RoomSummaryController.Listener, + OnBackPressed, + NotifsFabMenuView.Listener { private var modelBuildListener: OnModelBuildFinishedListener? = null private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel @@ -74,7 +81,9 @@ class RoomListFragment @Inject constructor( private val roomListViewModel: RoomListViewModel by fragmentViewModel() private lateinit var stateRestorer: LayoutManagerStateRestorer - override fun getLayoutResId() = R.layout.fragment_room_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomListBinding { + return FragmentRoomListBinding.inflate(inflater, container, false) + } private var hasUnreadRooms = false diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt index 306e951ab8..baa7057741 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt @@ -18,7 +18,9 @@ package im.vector.app.features.home.room.list.actions import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -27,9 +29,10 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding import im.vector.app.features.navigation.Navigator -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* +import kotlinx.parcelize.Parcelize + import javax.inject.Inject @Parcelize @@ -47,7 +50,9 @@ data class RoomListActionsArgs( /** * Bottom sheet fragment that shows room information with list of contextual actions */ -class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomListQuickActionsEpoxyController.Listener { +class RoomListQuickActionsBottomSheet : + VectorBaseBottomSheetDialogFragment(), + RoomListQuickActionsEpoxyController.Listener { private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel @Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool @@ -63,17 +68,19 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding { + return BottomSheetGenericListBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java) - bottomSheetRecyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) + views.views.bottomSheetRecyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) roomListActionsEpoxyController.listener = this } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.views.bottomSheetRecyclerView.cleanup() roomListActionsEpoxyController.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/widget/NotifsFabMenuView.kt b/vector/src/main/java/im/vector/app/features/home/room/list/widget/NotifsFabMenuView.kt index 7c96f40dbf..b196e0d670 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/widget/NotifsFabMenuView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/widget/NotifsFabMenuView.kt @@ -22,7 +22,7 @@ import androidx.constraintlayout.motion.widget.MotionLayout import androidx.core.view.isVisible import com.google.android.material.floatingactionbutton.FloatingActionButton import im.vector.app.R -import kotlinx.android.synthetic.main.motion_notifs_fab_menu_merge.view.* + class NotifsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) { diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt index 65f547a662..f00899d7f0 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt @@ -45,8 +45,8 @@ import im.vector.app.features.userdirectory.UserListSharedAction import im.vector.app.features.userdirectory.UserListSharedActionViewModel import im.vector.app.features.userdirectory.UserListViewModel import im.vector.app.features.userdirectory.UserListViewState -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.activity.* +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.failure.Failure import java.net.HttpURLConnection import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt b/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt index 5e8c5b3cca..f8d4061e01 100644 --- a/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt +++ b/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt @@ -19,13 +19,15 @@ package im.vector.app.features.invite import android.content.Context import android.util.AttributeSet import android.view.View +import android.widget.ImageView +import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.updateLayoutParams import im.vector.app.R import im.vector.app.core.di.HasScreenInjector import im.vector.app.core.platform.ButtonStateView import im.vector.app.features.home.AvatarRenderer -import kotlinx.android.synthetic.main.vector_invite_view.view.* + import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.util.toMatrixItem @@ -44,6 +46,13 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib SMALL } + private val inviteAvatarView: ImageView + private val inviteLabelView: TextView + private val inviteNameView: TextView + private val inviteIdentifierView: TextView + private val inviteAcceptView: ButtonStateView + private val inviteRejectView: ButtonStateView + @Inject lateinit var avatarRenderer: AvatarRenderer var callback: Callback? = null @@ -52,6 +61,7 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib context.injector().inject(this) } View.inflate(context, R.layout.vector_invite_view, this) + inviteAcceptView = findViewById(R.id.inviteAcceptView) inviteAcceptView.callback = object : ButtonStateView.Callback { override fun onButtonClicked() { callback?.onAcceptInvite() @@ -62,6 +72,7 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib } } + inviteRejectView = findViewById(R.id.inviteRejectView) inviteRejectView.callback = object : ButtonStateView.Callback { override fun onButtonClicked() { callback?.onRejectInvite() @@ -71,6 +82,11 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib callback?.onRejectInvite() } } + + inviteAvatarView = findViewById(R.id.inviteAvatarView) + inviteLabelView = findViewById(R.id.inviteLabelView) + inviteNameView = findViewById(R.id.inviteNameView) + inviteIdentifierView = findViewById(R.id.inviteIdentifierView) } fun render(sender: RoomMemberSummary, mode: Mode = Mode.LARGE, changeMembershipState: ChangeMembershipState) { diff --git a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt index 78cf2d9a62..729aa860d3 100644 --- a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt @@ -18,6 +18,7 @@ package im.vector.app.features.link import android.content.Intent import android.net.Uri +import android.view.LayoutInflater import androidx.appcompat.app.AlertDialog import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder @@ -25,6 +26,7 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.toast +import im.vector.app.databinding.ActivityProgressBinding import im.vector.app.features.login.LoginActivity import im.vector.app.features.login.LoginConfig import im.vector.app.features.permalink.PermalinkHandler @@ -38,7 +40,7 @@ import javax.inject.Inject /** * Dummy activity used to dispatch the vector URL links. */ -class LinkHandlerActivity : VectorBaseActivity() { +class LinkHandlerActivity : VectorBaseActivity() { @Inject lateinit var sessionHolder: ActiveSessionHolder @Inject lateinit var errorFormatter: ErrorFormatter @@ -48,7 +50,7 @@ class LinkHandlerActivity : VectorBaseActivity() { injector.inject(this) } - override fun getLayoutRes() = R.layout.activity_progress + override fun getBinding() = ActivityProgressBinding.inflate(layoutInflater) override fun initUiAndData() { val uri = intent.data diff --git a/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt index e3c1aa7b12..e537f31e78 100644 --- a/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/AbstractLoginFragment.kt @@ -21,6 +21,7 @@ import android.view.View import androidx.annotation.CallSuper import androidx.appcompat.app.AlertDialog import androidx.transition.TransitionInflater +import androidx.viewbinding.ViewBinding import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -35,7 +36,7 @@ import javax.net.ssl.HttpsURLConnection /** * Parent Fragment for all the login/registration screens */ -abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed { +abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed { protected val loginViewModel: LoginViewModel by activityViewModel() diff --git a/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt index 9b0a154100..c20f4ddd23 100644 --- a/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/AbstractSSOLoginFragment.kt @@ -21,10 +21,11 @@ import android.net.Uri import androidx.browser.customtabs.CustomTabsClient import androidx.browser.customtabs.CustomTabsServiceConnection import androidx.browser.customtabs.CustomTabsSession +import androidx.viewbinding.ViewBinding import com.airbnb.mvrx.withState import im.vector.app.core.utils.openUrlInChromeCustomTab -abstract class AbstractSSOLoginFragment : AbstractLoginFragment() { +abstract class AbstractSSOLoginFragment : AbstractLoginFragment() { // For sso private var customTabsServiceConnection: CustomTabsServiceConnection? = null diff --git a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt index 2e60fea660..99adda7b45 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt @@ -18,6 +18,7 @@ package im.vector.app.features.login import android.content.Context import android.content.Intent +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.CallSuper @@ -39,12 +40,13 @@ import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivityLoginBinding import im.vector.app.features.home.HomeActivity import im.vector.app.features.login.terms.LoginTermsFragment import im.vector.app.features.login.terms.LoginTermsFragmentArgument import im.vector.app.features.login.terms.toLocalizedLoginTerms import im.vector.app.features.pin.UnlockedActivity -import kotlinx.android.synthetic.main.activity_login.* + import org.matrix.android.sdk.api.auth.registration.FlowResult import org.matrix.android.sdk.api.auth.registration.Stage import org.matrix.android.sdk.api.extensions.tryOrNull @@ -53,7 +55,7 @@ import javax.inject.Inject /** * The LoginActivity manages the fragment navigation and also display the loading View */ -open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity { +open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity { private val loginViewModel: LoginViewModel by viewModel() @@ -84,7 +86,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedAc ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim) } - final override fun getLayoutRes() = R.layout.activity_login + final override fun getBinding() = ActivityLoginBinding.inflate(layoutInflater) override fun initUiAndData() { if (isFirstCreation()) { @@ -211,7 +213,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedAc } // Loading - loginLoading.isVisible = loginViewState.isLoading() + views.loginLoading.isVisible = loginViewState.isLoading() } private fun onWebLoginError(onWebLoginError: LoginViewEvents.OnWebLoginError) { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt index 6dd17a7d58..b01421d59b 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt @@ -23,6 +23,8 @@ import android.net.http.SslError import android.os.Build import android.os.Parcelable import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.ViewGroup import android.webkit.SslErrorHandler import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse @@ -33,8 +35,10 @@ import androidx.core.view.isVisible import com.airbnb.mvrx.args import im.vector.app.R import im.vector.app.core.utils.AssetReader -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_login_captcha.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginCaptchaBinding +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.internal.di.MoshiProvider import timber.log.Timber import java.net.URLDecoder @@ -51,9 +55,11 @@ data class LoginCaptchaFragmentArgument( */ class LoginCaptchaFragment @Inject constructor( private val assetReader: AssetReader -) : AbstractLoginFragment() { +) : AbstractLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_captcha + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginCaptchaBinding { + return FragmentLoginCaptchaBinding.inflate(inflater, container, false) + } private val params: LoginCaptchaFragmentArgument by args() @@ -61,7 +67,7 @@ class LoginCaptchaFragment @Inject constructor( @SuppressLint("SetJavaScriptEnabled") private fun setupWebView(state: LoginViewState) { - loginCaptchaWevView.settings.javaScriptEnabled = true + views.loginCaptchaWevView.settings.javaScriptEnabled = true val reCaptchaPage = assetReader.readAssetFile("reCaptchaPage.html") ?: error("missing asset reCaptchaPage.html") @@ -70,10 +76,10 @@ class LoginCaptchaFragment @Inject constructor( val encoding = "utf-8" val homeServerUrl = state.homeServerUrl ?: error("missing url of homeserver") - loginCaptchaWevView.loadDataWithBaseURL(homeServerUrl, html, mime, encoding, null) - loginCaptchaWevView.requestLayout() + views.loginCaptchaWevView.loadDataWithBaseURL(homeServerUrl, html, mime, encoding, null) + views.loginCaptchaWevView.requestLayout() - loginCaptchaWevView.webViewClient = object : WebViewClient() { + views.loginCaptchaWevView.webViewClient = object : WebViewClient() { override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { super.onPageStarted(view, url, favicon) @@ -82,7 +88,7 @@ class LoginCaptchaFragment @Inject constructor( } // Show loader - loginCaptchaProgress.isVisible = true + views.loginCaptchaProgress.isVisible = true } override fun onPageFinished(view: WebView, url: String) { @@ -93,7 +99,7 @@ class LoginCaptchaFragment @Inject constructor( } // Hide loader - loginCaptchaProgress.isVisible = false + views.loginCaptchaProgress.isVisible = false } override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginConfig.kt b/vector/src/main/java/im/vector/app/features/login/LoginConfig.kt index 47ce99754f..9c02ebae44 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginConfig.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginConfig.kt @@ -18,7 +18,7 @@ package im.vector.app.features.login import android.net.Uri import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize /** * Parameters extracted from a configuration url diff --git a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt index 9cb3428c80..ba89b981de 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.login import android.os.Build import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.autofill.HintConstants import androidx.core.text.isDigitsOnly @@ -32,11 +34,13 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.showPassword import im.vector.app.core.extensions.toReducedUrl +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.FragmentLoginBinding import io.reactivex.Observable import io.reactivex.functions.BiFunction import io.reactivex.rxkotlin.subscribeBy -import kotlinx.android.synthetic.main.fragment_login.* -import kotlinx.android.synthetic.main.fragment_login_signup_signin_selection.* + + import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.api.failure.isInvalidPassword @@ -50,7 +54,7 @@ import javax.inject.Inject * In signup mode: * - the user is asked for login and password */ -class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { +class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { private var passwordShown = false private var isSignupMode = false @@ -59,7 +63,9 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { // waiting for https://github.com/matrix-org/synapse/issues/7576 private var isNumericOnlyUserIdForbidden = false - override fun getLayoutResId() = R.layout.fragment_login + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginBinding { + return FragmentLoginBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -68,7 +74,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { setupForgottenPasswordButton() setupPasswordReveal() - passwordField.setOnEditorActionListener { _, actionId, _ -> + views.passwordField.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE) { submit() return@setOnEditorActionListener true @@ -78,7 +84,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { } private fun setupForgottenPasswordButton() { - forgetPasswordButton.setOnClickListener { forgetPasswordClicked() } + views.forgetPasswordButton.setOnClickListener { forgetPasswordClicked() } } private fun setupAutoFill(state: LoginViewState) { @@ -86,15 +92,15 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { when (state.signMode) { SignMode.Unknown -> error("developer error") SignMode.SignUp -> { - loginField.setAutofillHints(HintConstants.AUTOFILL_HINT_NEW_USERNAME) - passwordField.setAutofillHints(HintConstants.AUTOFILL_HINT_NEW_PASSWORD) - loginSocialLoginButtons.mode = SocialLoginButtonsView.Mode.MODE_SIGN_UP + views.loginField.setAutofillHints(HintConstants.AUTOFILL_HINT_NEW_USERNAME) + views.passwordField.setAutofillHints(HintConstants.AUTOFILL_HINT_NEW_PASSWORD) + views.loginSocialLoginButtons.mode = SocialLoginButtonsView.Mode.MODE_SIGN_UP } SignMode.SignIn, SignMode.SignInWithMatrixId -> { - loginField.setAutofillHints(HintConstants.AUTOFILL_HINT_USERNAME) - passwordField.setAutofillHints(HintConstants.AUTOFILL_HINT_PASSWORD) - loginSocialLoginButtons.mode = SocialLoginButtonsView.Mode.MODE_SIGN_IN + views.loginField.setAutofillHints(HintConstants.AUTOFILL_HINT_USERNAME) + views.passwordField.setAutofillHints(HintConstants.AUTOFILL_HINT_PASSWORD) + views.loginSocialLoginButtons.mode = SocialLoginButtonsView.Mode.MODE_SIGN_IN } }.exhaustive } @@ -103,21 +109,21 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { private fun submit() { cleanupUi() - val login = loginField.text.toString() - val password = passwordField.text.toString() + val login = views.loginField.text.toString() + val password = views.passwordField.text.toString() // This can be called by the IME action, so deal with empty cases var error = 0 if (login.isEmpty()) { - loginFieldTil.error = getString(if (isSignupMode) R.string.error_empty_field_choose_user_name else R.string.error_empty_field_enter_user_name) + views.loginFieldTil.error = getString(if (isSignupMode) R.string.error_empty_field_choose_user_name else R.string.error_empty_field_enter_user_name) error++ } if (isSignupMode && isNumericOnlyUserIdForbidden && login.isDigitsOnly()) { - loginFieldTil.error = "The homeserver does not accept username with only digits." + views.loginFieldTil.error = "The homeserver does not accept username with only digits." error++ } if (password.isEmpty()) { - passwordFieldTil.error = getString(if (isSignupMode) R.string.error_empty_field_choose_password else R.string.error_empty_field_your_password) + views.passwordFieldTil.error = getString(if (isSignupMode) R.string.error_empty_field_choose_password else R.string.error_empty_field_your_password) error++ } @@ -127,13 +133,13 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { } private fun cleanupUi() { - loginSubmit.hideKeyboard() - loginFieldTil.error = null - passwordFieldTil.error = null + views.loginSubmit.hideKeyboard() + views.loginFieldTil.error = null + views.passwordFieldTil.error = null } private fun setupUi(state: LoginViewState) { - loginFieldTil.hint = getString(when (state.signMode) { + views.loginFieldTil.hint = getString(when (state.signMode) { SignMode.Unknown -> error("developer error") SignMode.SignUp -> R.string.login_signup_username_hint SignMode.SignIn -> R.string.login_signin_username_hint @@ -142,10 +148,10 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { // Handle direct signin first if (state.signMode == SignMode.SignInWithMatrixId) { - loginServerIcon.isVisible = false - loginTitle.text = getString(R.string.login_signin_matrix_id_title) - loginNotice.text = getString(R.string.login_signin_matrix_id_notice) - loginPasswordNotice.isVisible = true + views.loginServerIcon.isVisible = false + views.loginTitle.text = getString(R.string.login_signin_matrix_id_title) + views.loginNotice.text = getString(R.string.login_signin_matrix_id_notice) + views.loginPasswordNotice.isVisible = true } else { val resId = when (state.signMode) { SignMode.Unknown -> error("developer error") @@ -156,45 +162,45 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { when (state.serverType) { ServerType.MatrixOrg -> { - loginServerIcon.isVisible = true - loginServerIcon.setImageResource(R.drawable.ic_logo_matrix_org) - loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl()) - loginNotice.text = getString(R.string.login_server_matrix_org_text) + views.loginServerIcon.isVisible = true + views.loginServerIcon.setImageResource(R.drawable.ic_logo_matrix_org) + views.loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl()) + views.loginNotice.text = getString(R.string.login_server_matrix_org_text) } ServerType.EMS -> { - loginServerIcon.isVisible = true - loginServerIcon.setImageResource(R.drawable.ic_logo_element_matrix_services) - loginTitle.text = getString(resId, "Element Matrix Services") - loginNotice.text = getString(R.string.login_server_modular_text) + views.loginServerIcon.isVisible = true + views.loginServerIcon.setImageResource(R.drawable.ic_logo_element_matrix_services) + views.loginTitle.text = getString(resId, "Element Matrix Services") + views.loginNotice.text = getString(R.string.login_server_modular_text) } ServerType.Other -> { - loginServerIcon.isVisible = false - loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl()) - loginNotice.text = getString(R.string.login_server_other_text) + views.loginServerIcon.isVisible = false + views.loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl()) + views.loginNotice.text = getString(R.string.login_server_other_text) } ServerType.Unknown -> Unit /* Should not happen */ } - loginPasswordNotice.isVisible = false + views.loginPasswordNotice.isVisible = false if (state.loginMode is LoginMode.SsoAndPassword) { - loginSocialLoginContainer.isVisible = true - loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders - loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener { + views.loginSocialLoginContainer.isVisible = true + views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders + views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener { override fun onProviderSelected(id: String?) { openInCustomTab(state.getSsoUrl(id)) } } } else { - loginSocialLoginContainer.isVisible = false - loginSocialLoginButtons.ssoIdentityProviders = null + views.loginSocialLoginContainer.isVisible = false + views.loginSocialLoginButtons.ssoIdentityProviders = null } } } private fun setupButtons(state: LoginViewState) { - forgetPasswordButton.isVisible = state.signMode == SignMode.SignIn + views.forgetPasswordButton.isVisible = state.signMode == SignMode.SignIn - loginSubmit.text = getString(when (state.signMode) { + views.loginSubmit.text = getString(when (state.signMode) { SignMode.Unknown -> error("developer error") SignMode.SignUp -> R.string.login_signup_submit SignMode.SignIn, @@ -203,19 +209,19 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { } private fun setupSubmitButton() { - loginSubmit.setOnClickListener { submit() } + views.loginSubmit.setOnClickListener { submit() } Observable .combineLatest( - loginField.textChanges().map { it.trim().isNotEmpty() }, - passwordField.textChanges().map { it.isNotEmpty() }, + views.loginField.textChanges().map { it.trim().isNotEmpty() }, + views.passwordField.textChanges().map { it.isNotEmpty() }, BiFunction { isLoginNotEmpty, isPasswordNotEmpty -> isLoginNotEmpty && isPasswordNotEmpty } ) .subscribeBy { - loginFieldTil.error = null - passwordFieldTil.error = null - loginSubmit.isEnabled = it + views.loginFieldTil.error = null + views.passwordFieldTil.error = null + views.loginSubmit.isEnabled = it } .disposeOnDestroyView() } @@ -227,7 +233,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { private fun setupPasswordReveal() { passwordShown = false - passwordReveal.setOnClickListener { + views.passwordReveal.setOnClickListener { passwordShown = !passwordShown renderPasswordField() @@ -237,14 +243,14 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { } private fun renderPasswordField() { - passwordField.showPassword(passwordShown) + views.passwordField.showPassword(passwordShown) if (passwordShown) { - passwordReveal.setImageResource(R.drawable.ic_eye_closed) - passwordReveal.contentDescription = getString(R.string.a11y_hide_password) + views.passwordReveal.setImageResource(R.drawable.ic_eye_closed) + views.passwordReveal.contentDescription = getString(R.string.a11y_hide_password) } else { - passwordReveal.setImageResource(R.drawable.ic_eye) - passwordReveal.contentDescription = getString(R.string.a11y_show_password) + views.passwordReveal.setImageResource(R.drawable.ic_eye) + views.passwordReveal.contentDescription = getString(R.string.a11y_show_password) } } @@ -256,9 +262,9 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { // Show M_WEAK_PASSWORD error in the password field if (throwable is Failure.ServerError && throwable.error.code == MatrixError.M_WEAK_PASSWORD) { - passwordFieldTil.error = errorFormatter.toHumanReadable(throwable) + views.passwordFieldTil.error = errorFormatter.toHumanReadable(throwable) } else { - loginFieldTil.error = errorFormatter.toHumanReadable(throwable) + views.loginFieldTil.error = errorFormatter.toHumanReadable(throwable) } } @@ -282,14 +288,14 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { && error.error.code == MatrixError.M_FORBIDDEN && error.error.message.isEmpty()) { // Login with email, but email unknown - loginFieldTil.error = getString(R.string.login_login_with_email_error) + views.loginFieldTil.error = getString(R.string.login_login_with_email_error) } else { // Trick to display the error without text. - loginFieldTil.error = " " + views.loginFieldTil.error = " " if (error.isInvalidPassword() && spaceInPassword()) { - passwordFieldTil.error = getString(R.string.auth_invalid_login_param_space_in_password) + views.passwordFieldTil.error = getString(R.string.auth_invalid_login_param_space_in_password) } else { - passwordFieldTil.error = errorFormatter.toHumanReadable(error) + views.passwordFieldTil.error = errorFormatter.toHumanReadable(error) } } } @@ -311,5 +317,5 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() { /** * Detect if password ends or starts with spaces */ - private fun spaceInPassword() = passwordField.text.toString().let { it.trim() != it } + private fun spaceInPassword() = views.passwordField.text.toString().let { it.trim() != it } } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt index 70ef97c209..220577f2a2 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt @@ -20,7 +20,9 @@ import android.os.Build import android.os.Bundle import android.os.Parcelable import android.text.InputType +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.autofill.HintConstants import androidx.core.view.isVisible import com.airbnb.mvrx.args @@ -31,8 +33,10 @@ import im.vector.app.R import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.isEmail import im.vector.app.core.extensions.setTextOrHide -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_login_generic_text_input_form.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginGenericTextInputFormBinding +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.auth.registration.RegisterThreePid import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.is401 @@ -54,11 +58,13 @@ data class LoginGenericTextInputFormFragmentArgument( /** * In this screen, the user is asked for a text input */ -class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFragment() { +class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFragment() { private val params: LoginGenericTextInputFormFragmentArgument by args() - override fun getLayoutResId() = R.layout.fragment_login_generic_text_input_form + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginGenericTextInputFormBinding { + return FragmentLoginGenericTextInputFormBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginMode.kt b/vector/src/main/java/im/vector/app/features/login/LoginMode.kt index 14accefc00..2be198ab96 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginMode.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginMode.kt @@ -17,7 +17,7 @@ package im.vector.app.features.login import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider sealed class LoginMode : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt index 5b6fc362cd..1fb738710e 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.login import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading @@ -28,23 +30,27 @@ import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.isEmail import im.vector.app.core.extensions.showPassword import im.vector.app.core.extensions.toReducedUrl +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginResetPasswordBinding import io.reactivex.Observable import io.reactivex.functions.BiFunction import io.reactivex.rxkotlin.subscribeBy -import kotlinx.android.synthetic.main.fragment_login_reset_password.* + import javax.inject.Inject /** * In this screen, the user is asked for email and new password to reset his password */ -class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment() { +class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment() { private var passwordShown = false // Show warning only once private var showWarning = true - override fun getLayoutResId() = R.layout.fragment_login_reset_password + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordBinding { + return FragmentLoginResetPasswordBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt index 08678c020c..14f2261874 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordMailConfirmationFragment.kt @@ -17,30 +17,36 @@ package im.vector.app.features.login import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Success import im.vector.app.R -import kotlinx.android.synthetic.main.fragment_login_reset_password_mail_confirmation.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginResetPasswordMailConfirmationBinding + import org.matrix.android.sdk.api.failure.is401 import javax.inject.Inject /** * In this screen, the user is asked to check his email and to click on a button once it's done */ -class LoginResetPasswordMailConfirmationFragment @Inject constructor() : AbstractLoginFragment() { +class LoginResetPasswordMailConfirmationFragment @Inject constructor() : AbstractLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_reset_password_mail_confirmation + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordMailConfirmationBinding { + return FragmentLoginResetPasswordMailConfirmationBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - resetPasswordMailConfirmationSubmit.setOnClickListener { submit() } + views.resetPasswordMailConfirmationSubmit.setOnClickListener { submit() } } private fun setupUi(state: LoginViewState) { - resetPasswordMailConfirmationNotice.text = getString(R.string.login_reset_password_mail_confirmation_notice, state.resetPasswordEmail) + views.resetPasswordMailConfirmationNotice.text = getString(R.string.login_reset_password_mail_confirmation_notice, state.resetPasswordEmail) } private fun submit() { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt index 1a428f57df..6dea50bbd2 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordSuccessFragment.kt @@ -17,22 +17,29 @@ package im.vector.app.features.login import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import im.vector.app.R -import kotlinx.android.synthetic.main.fragment_login_reset_password_success.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginResetPasswordBinding +import im.vector.app.databinding.FragmentLoginResetPasswordSuccessBinding + import javax.inject.Inject /** * In this screen, we confirm to the user that his password has been reset */ -class LoginResetPasswordSuccessFragment @Inject constructor() : AbstractLoginFragment() { +class LoginResetPasswordSuccessFragment @Inject constructor() : AbstractLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_reset_password_success + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginResetPasswordSuccessBinding { + return FragmentLoginResetPasswordSuccessBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - resetPasswordSuccessSubmit.setOnClickListener { submit() } + views.resetPasswordSuccessSubmit.setOnClickListener { submit() } } private fun submit() { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt index c365844c6e..13430fe241 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginServerSelectionFragment.kt @@ -17,19 +17,25 @@ package im.vector.app.features.login import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import im.vector.app.R import im.vector.app.core.utils.openUrlInChromeCustomTab -import kotlinx.android.synthetic.main.fragment_login_server_selection.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginServerSelectionBinding + import me.gujun.android.span.span import javax.inject.Inject /** * In this screen, the user will choose between matrix.org, modular or other type of homeserver */ -class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment() { +class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_server_selection + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginServerSelectionBinding { + return FragmentLoginServerSelectionBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -39,19 +45,19 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment } private fun initViews() { - loginServerChoiceEmsLearnMore.setOnClickListener { learnMore() } - loginServerChoiceMatrixOrg.setOnClickListener { selectMatrixOrg() } - loginServerChoiceEms.setOnClickListener { selectEMS() } - loginServerChoiceOther.setOnClickListener { selectOther() } - loginServerIKnowMyIdSubmit.setOnClickListener { loginWithMatrixId() } + views.loginServerChoiceEmsLearnMore.setOnClickListener { learnMore() } + views.loginServerChoiceMatrixOrg.setOnClickListener { selectMatrixOrg() } + views.loginServerChoiceEms.setOnClickListener { selectEMS() } + views.loginServerChoiceOther.setOnClickListener { selectOther() } + views.loginServerIKnowMyIdSubmit.setOnClickListener { loginWithMatrixId() } } private fun updateSelectedChoice(state: LoginViewState) { - loginServerChoiceMatrixOrg.isChecked = state.serverType == ServerType.MatrixOrg + views.loginServerChoiceMatrixOrg.isChecked = state.serverType == ServerType.MatrixOrg } private fun initTextViews() { - loginServerChoiceEmsLearnMore.text = span { + views.loginServerChoiceEmsLearnMore.text = span { text = getString(R.string.login_server_modular_learn_more) textDecorationLine = "underline" } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt index 7a4d60a2bd..2bc969e15f 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.login import android.annotation.SuppressLint import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.view.inputmethod.EditorInfo import android.widget.ArrayAdapter import androidx.core.view.isInvisible @@ -30,7 +32,9 @@ import im.vector.app.R import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.utils.ensureProtocol import im.vector.app.core.utils.openUrlInChromeCustomTab -import kotlinx.android.synthetic.main.fragment_login_server_url_form.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginServerUrlFormBinding + import org.matrix.android.sdk.api.failure.Failure import java.net.UnknownHostException import javax.inject.Inject @@ -38,9 +42,11 @@ import javax.inject.Inject /** * In this screen, the user is prompted to enter a homeserver url */ -class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() { +class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_server_url_form + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginServerUrlFormBinding { + return FragmentLoginServerUrlFormBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt index 36ef6eef61..072428170e 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt @@ -17,20 +17,26 @@ package im.vector.app.features.login import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isVisible import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.toReducedUrl -import kotlinx.android.synthetic.main.fragment_login_signup_signin_selection.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginSignupSigninSelectionBinding + import javax.inject.Inject /** * In this screen, the user is asked to sign up or to sign in to the homeserver */ -class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLoginFragment() { +class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_signup_signin_selection + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginSignupSigninSelectionBinding { + return FragmentLoginSignupSigninSelectionBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt index 7cb3e30810..c6927b4611 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt @@ -17,17 +17,23 @@ package im.vector.app.features.login import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import im.vector.app.R -import kotlinx.android.synthetic.main.fragment_login_splash.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginSplashBinding + import javax.inject.Inject /** * In this screen, the user is viewing an introduction to what he can do with this application */ -class LoginSplashFragment @Inject constructor() : AbstractLoginFragment() { +class LoginSplashFragment @Inject constructor() : AbstractLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_splash + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginSplashBinding { + return FragmentLoginSplashBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -36,7 +42,7 @@ class LoginSplashFragment @Inject constructor() : AbstractLoginFragment() { } private fun setupViews() { - loginSplashSubmit.setOnClickListener { getStarted() } + views.loginSplashSubmit.setOnClickListener { getStarted() } } private fun getStarted() { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt index 6f86f1c9d6..ac19d595d6 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginWaitForEmailFragment.kt @@ -18,11 +18,15 @@ package im.vector.app.features.login import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.args import im.vector.app.R -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_login_wait_for_email.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginWaitForEmailBinding +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.failure.is401 import javax.inject.Inject @@ -34,11 +38,13 @@ data class LoginWaitForEmailFragmentArgument( /** * In this screen, the user is asked to check his emails */ -class LoginWaitForEmailFragment @Inject constructor() : AbstractLoginFragment() { +class LoginWaitForEmailFragment @Inject constructor() : AbstractLoginFragment() { private val params: LoginWaitForEmailFragmentArgument by args() - override fun getLayoutResId() = R.layout.fragment_login_wait_for_email + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginWaitForEmailBinding { + return FragmentLoginWaitForEmailBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -59,7 +65,7 @@ class LoginWaitForEmailFragment @Inject constructor() : AbstractLoginFragment() } private fun setupUi() { - loginWaitForEmailNotice.text = getString(R.string.login_wait_for_email_notice, params.email) + views.loginWaitForEmailNotice.text = getString(R.string.login_wait_for_email_notice, params.email) } override fun onError(throwable: Throwable) { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt index 78a24abfd3..eaa7471da2 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt @@ -24,7 +24,9 @@ import android.graphics.Bitmap import android.net.http.SslError import android.os.Bundle import android.view.KeyEvent +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.webkit.SslErrorHandler import android.webkit.WebView import android.webkit.WebViewClient @@ -33,9 +35,11 @@ import com.airbnb.mvrx.activityViewModel import im.vector.app.R import im.vector.app.core.extensions.appendParamToUrl import im.vector.app.core.utils.AssetReader +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginWebBinding import im.vector.app.features.signout.soft.SoftLogoutAction import im.vector.app.features.signout.soft.SoftLogoutViewModel -import kotlinx.android.synthetic.main.fragment_login_web.* + import org.matrix.android.sdk.api.auth.LOGIN_FALLBACK_PATH import org.matrix.android.sdk.api.auth.REGISTER_FALLBACK_PATH import org.matrix.android.sdk.api.auth.data.Credentials @@ -50,9 +54,11 @@ import javax.inject.Inject */ class LoginWebFragment @Inject constructor( private val assetReader: AssetReader -) : AbstractLoginFragment() { +) : AbstractLoginFragment() { - override fun getLayoutResId() = R.layout.fragment_login_web + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginWebBinding { + return FragmentLoginWebBinding.inflate(inflater, container, false) + } private var isWebViewLoaded = false private var isForSessionRecovery = false @@ -60,7 +66,7 @@ class LoginWebFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setupToolbar(loginWebToolbar) + setupToolbar(views.loginWebToolbar) } override fun updateWithState(state: LoginViewState) { @@ -75,7 +81,7 @@ class LoginWebFragment @Inject constructor( } private fun setupTitle(state: LoginViewState) { - loginWebToolbar.title = when (state.signMode) { + views.loginWebToolbar.title = when (state.signMode) { SignMode.SignIn -> getString(R.string.login_signin) else -> getString(R.string.login_signup) } @@ -83,15 +89,15 @@ class LoginWebFragment @Inject constructor( @SuppressLint("SetJavaScriptEnabled") private fun setupWebView(state: LoginViewState) { - loginWebWebView.settings.javaScriptEnabled = true + views.loginWebWebView.settings.javaScriptEnabled = true // Enable local storage to support SSO with Firefox accounts - loginWebWebView.settings.domStorageEnabled = true - loginWebWebView.settings.databaseEnabled = true + views.loginWebWebView.settings.domStorageEnabled = true + views.loginWebWebView.settings.databaseEnabled = true // Due to https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html, we hack // the user agent to bypass the limitation of Google, as a quick fix (a proper solution will be to use the SSO SDK) - loginWebWebView.settings.userAgentString = "Mozilla/5.0 Google" + views.loginWebWebView.settings.userAgentString = "Mozilla/5.0 Google" // AppRTC requires third party cookies to work val cookieManager = android.webkit.CookieManager.getInstance() @@ -128,9 +134,9 @@ class LoginWebFragment @Inject constructor( } } - loginWebWebView.loadUrl(url) + views.loginWebWebView.loadUrl(url) - loginWebWebView.webViewClient = object : WebViewClient() { + views.loginWebWebView.webViewClient = object : WebViewClient() { override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { AlertDialog.Builder(requireActivity()) @@ -158,7 +164,7 @@ class LoginWebFragment @Inject constructor( override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { super.onPageStarted(view, url, favicon) - loginWebToolbar.subtitle = url + views.loginWebToolbar.subtitle = url } override fun onPageFinished(view: WebView, url: String) { @@ -259,9 +265,9 @@ class LoginWebFragment @Inject constructor( override fun onBackPressed(toolbarButton: Boolean): Boolean { return when { - toolbarButton -> super.onBackPressed(toolbarButton) - loginWebWebView.canGoBack() -> loginWebWebView.goBack().run { true } - else -> super.onBackPressed(toolbarButton) + toolbarButton -> super.onBackPressed(toolbarButton) + views.loginWebWebView.canGoBack() -> views.loginWebWebView.goBack().run { true } + else -> super.onBackPressed(toolbarButton) } } } diff --git a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt index 8561b1035a..5ec523b9db 100755 --- a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsFragment.kt @@ -18,18 +18,22 @@ package im.vector.app.features.login.terms import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.args 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.toReducedUrl import im.vector.app.core.utils.openUrlInChromeCustomTab +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLoginTermsBinding import im.vector.app.features.login.AbstractLoginFragment import im.vector.app.features.login.LoginAction import im.vector.app.features.login.LoginViewState -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_login_terms.* +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.internal.auth.registration.LocalizedFlowDataLoginTerms import javax.inject.Inject @@ -43,12 +47,14 @@ data class LoginTermsFragmentArgument( */ class LoginTermsFragment @Inject constructor( private val policyController: PolicyController -) : AbstractLoginFragment(), +) : AbstractLoginFragment(), PolicyController.PolicyControllerListener { private val params: LoginTermsFragmentArgument by args() - override fun getLayoutResId() = R.layout.fragment_login_terms + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginTermsBinding { + return FragmentLoginTermsBinding.inflate(inflater, container, false) + } private var loginTermsViewState: LoginTermsViewState = LoginTermsViewState(emptyList()) @@ -56,7 +62,7 @@ class LoginTermsFragment @Inject constructor( super.onViewCreated(view, savedInstanceState) setupViews() - loginTermsPolicyList.configureWith(policyController) + views.loginTermsPolicyList.configureWith(policyController) policyController.listener = this val list = ArrayList() @@ -70,11 +76,11 @@ class LoginTermsFragment @Inject constructor( } private fun setupViews() { - loginTermsSubmit.setOnClickListener { submit() } + views.loginTermsSubmit.setOnClickListener { submit() } } override fun onDestroyView() { - loginTermsPolicyList.cleanup() + views.loginTermsPolicyList.cleanup() policyController.listener = null super.onDestroyView() } @@ -83,7 +89,7 @@ class LoginTermsFragment @Inject constructor( policyController.setData(loginTermsViewState.localizedFlowDataLoginTermsChecked) // Button is enabled only if all checkboxes are checked - loginTermsSubmit.isEnabled = loginTermsViewState.allChecked() + views.loginTermsSubmit.isEnabled = loginTermsViewState.allChecked() } override fun setChecked(localizedFlowDataLoginTerms: LocalizedFlowDataLoginTerms, isChecked: Boolean) { diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt index 69f30bb470..1b0ccc66b5 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt @@ -18,7 +18,9 @@ package im.vector.app.features.matrixto import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isInvisible import androidx.core.view.isVisible import com.airbnb.mvrx.Fail @@ -32,12 +34,15 @@ import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetMatrixToCardBinding import im.vector.app.features.home.AvatarRenderer -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_matrix_to_card.* +import kotlinx.parcelize.Parcelize + import javax.inject.Inject -class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() { +class MatrixToBottomSheet : + VectorBaseBottomSheetDialogFragment() { @Parcelize data class MatrixToArgs( @@ -55,7 +60,9 @@ class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() { private var interactionListener: InteractionListener? = null - override fun getLayoutResId() = R.layout.bottom_sheet_matrix_to_card + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetMatrixToCardBinding { + return BottomSheetMatrixToCardBinding.inflate(inflater, container, false) + } private val viewModel by fragmentViewModel(MatrixToBottomSheetViewModel::class) @@ -67,19 +74,19 @@ class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() { super.invalidate() when (val item = state.matrixItem) { Uninitialized -> { - matrixToCardContentLoading.isVisible = false - matrixToCardUserContentVisibility.isVisible = false + views.matrixToCardContentLoading.isVisible = false + views.matrixToCardUserContentVisibility.isVisible = false } is Loading -> { - matrixToCardContentLoading.isVisible = true - matrixToCardUserContentVisibility.isVisible = false + views.matrixToCardContentLoading.isVisible = true + views.matrixToCardUserContentVisibility.isVisible = false } is Success -> { - matrixToCardContentLoading.isVisible = false - matrixToCardUserContentVisibility.isVisible = true - matrixToCardNameText.setTextOrHide(item.invoke().displayName) - matrixToCardUserIdText.setTextOrHide(item.invoke().id) - avatarRenderer.render(item.invoke(), matrixToCardAvatar) + views.matrixToCardContentLoading.isVisible = false + views.matrixToCardUserContentVisibility.isVisible = true + views.matrixToCardNameText.setTextOrHide(item.invoke().displayName) + views.matrixToCardUserIdText.setTextOrHide(item.invoke().id) + avatarRenderer.render(item.invoke(), views.matrixToCardAvatar) } is Fail -> { // TODO display some error copy? @@ -89,29 +96,29 @@ class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() { when (state.startChattingState) { Uninitialized -> { - matrixToCardButtonLoading.isVisible = false - matrixToCardSendMessageButton.isVisible = false + views.matrixToCardButtonLoading.isVisible = false + views.matrixToCardSendMessageButton.isVisible = false } is Success -> { - matrixToCardButtonLoading.isVisible = false - matrixToCardSendMessageButton.isVisible = true + views.matrixToCardButtonLoading.isVisible = false + views.matrixToCardSendMessageButton.isVisible = true } is Fail -> { - matrixToCardButtonLoading.isVisible = false - matrixToCardSendMessageButton.isVisible = true + views.matrixToCardButtonLoading.isVisible = false + views.matrixToCardSendMessageButton.isVisible = true // TODO display some error copy? dismiss() } is Loading -> { - matrixToCardButtonLoading.isVisible = true - matrixToCardSendMessageButton.isInvisible = true + views.matrixToCardButtonLoading.isVisible = true + views.matrixToCardSendMessageButton.isInvisible = true } } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - matrixToCardSendMessageButton.debouncedClicks { + views.matrixToCardSendMessageButton.debouncedClicks { withState(viewModel) { it.matrixItem.invoke()?.let { item -> viewModel.handle(MatrixToAction.StartChattingWithUser(item)) diff --git a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt index 195421ff58..3eff056ae9 100644 --- a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt @@ -19,29 +19,32 @@ package im.vector.app.features.media import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.LayoutInflater import androidx.core.net.toUri import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ScreenComponent import im.vector.app.core.platform.VectorBaseActivity -import kotlinx.android.synthetic.main.activity_big_image_viewer.* +import im.vector.app.databinding.ActivityBigImageViewerBinding + import javax.inject.Inject /** * Simple Activity to display an avatar in fullscreen */ -class BigImageViewerActivity : VectorBaseActivity() { +class BigImageViewerActivity : VectorBaseActivity() { @Inject lateinit var sessionHolder: ActiveSessionHolder + override fun getBinding() = ActivityBigImageViewerBinding.inflate(layoutInflater) + override fun injectWith(injector: ScreenComponent) { injector.inject(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_big_image_viewer) - setSupportActionBar(bigImageViewerToolbar) + setSupportActionBar(views.bigImageViewerToolbar) supportActionBar?.apply { title = intent.getStringExtra(EXTRA_TITLE) setHomeButtonEnabled(true) @@ -56,7 +59,7 @@ class BigImageViewerActivity : VectorBaseActivity() { if (uri == null) { finish() } else { - bigImageViewerImageView.showImage(uri) + views.bigImageViewerImageView.showImage(uri) } } diff --git a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt index 4670c82db1..75c7912646 100644 --- a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt @@ -39,7 +39,7 @@ import im.vector.app.core.glide.GlideRequests import im.vector.app.core.ui.model.Size import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.isLocalFile -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt diff --git a/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt index e7f4806e31..c632a008ce 100644 --- a/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt @@ -42,7 +42,7 @@ import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ThemeUtils import im.vector.lib.attachmentviewer.AttachmentCommands import im.vector.lib.attachmentviewer.AttachmentViewerActivity -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import timber.log.Timber import javax.inject.Inject import kotlin.system.measureTimeMillis diff --git a/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt b/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt index d8eddc7331..c771eece8f 100644 --- a/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt @@ -25,7 +25,7 @@ import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.utils.isLocalFile -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt import timber.log.Timber diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt index e8064aaec5..02c9c7f717 100644 --- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt @@ -23,16 +23,19 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.FragmentProgressBinding import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.LoadingFragment import im.vector.app.features.login.LoginActivity import javax.inject.Inject -class PermalinkHandlerActivity : VectorBaseActivity() { +class PermalinkHandlerActivity : VectorBaseActivity() { @Inject lateinit var permalinkHandler: PermalinkHandler @Inject lateinit var sessionHolder: ActiveSessionHolder + override fun getBinding() = FragmentProgressBinding.inflate(layoutInflater) + override fun injectWith(injector: ScreenComponent) { injector.inject(this) } diff --git a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt index 2e6a0b6c08..4828895ec1 100644 --- a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt +++ b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt @@ -24,8 +24,9 @@ import im.vector.app.R import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding -class PinActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity { +class PinActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity { companion object { fun newIntent(context: Context, args: PinArgs): Intent { @@ -35,7 +36,7 @@ class PinActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity } } - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() =ActivitySimpleBinding.inflate(layoutInflater) override fun initUiAndData() { if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/pin/PinFragment.kt b/vector/src/main/java/im/vector/app/features/pin/PinFragment.kt index 1aa4846f38..8dcb1689c7 100644 --- a/vector/src/main/java/im/vector/app/features/pin/PinFragment.kt +++ b/vector/src/main/java/im/vector/app/features/pin/PinFragment.kt @@ -19,7 +19,9 @@ package im.vector.app.features.pin import android.app.Activity import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.lifecycle.lifecycleScope @@ -30,10 +32,12 @@ import im.vector.app.R import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.toast +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentPinBinding import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs import im.vector.app.features.settings.VectorPreferences -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import kotlinx.coroutines.launch import javax.inject.Inject @@ -45,11 +49,13 @@ data class PinArgs( class PinFragment @Inject constructor( private val pinCodeStore: PinCodeStore, private val vectorPreferences: VectorPreferences -) : VectorBaseFragment() { +) : VectorBaseFragment() { private val fragmentArgs: PinArgs by args() - override fun getLayoutResId() = R.layout.fragment_pin + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentPinBinding { + return FragmentPinBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt index 8a5126a160..fc30c2808b 100644 --- a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt @@ -27,10 +27,11 @@ import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding -class QrCodeScannerActivity : VectorBaseActivity() { +class QrCodeScannerActivity : VectorBaseActivity() { - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun injectWith(injector: ScreenComponent) { injector.inject(this) diff --git a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerFragment.kt b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerFragment.kt index 6371e3c29b..af3ffdaa94 100644 --- a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerFragment.kt @@ -16,31 +16,37 @@ package im.vector.app.features.qrcode +import android.view.LayoutInflater +import android.view.ViewGroup import com.google.zxing.Result import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_qr_code_scanner.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentQrCodeScannerBinding + import me.dm7.barcodescanner.zxing.ZXingScannerView import javax.inject.Inject class QrCodeScannerFragment @Inject constructor() - : VectorBaseFragment(), + : VectorBaseFragment(), ZXingScannerView.ResultHandler { - override fun getLayoutResId() = R.layout.fragment_qr_code_scanner + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeScannerBinding { + return FragmentQrCodeScannerBinding.inflate(inflater, container, false) + } override fun onResume() { super.onResume() // Register ourselves as a handler for scan results. - scannerView.setResultHandler(this) + views.scannerView.setResultHandler(this) // Start camera on resume - scannerView.startCamera() + views.scannerView.startCamera() } override fun onPause() { super.onPause() // Stop camera on pause - scannerView.stopCamera() + views.scannerView.stopCamera() } override fun handleResult(rawResult: Result?) { diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt index 830f49f92f..38ff9ce5ae 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt @@ -16,6 +16,7 @@ package im.vector.app.features.rageshake +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.widget.Toast @@ -24,32 +25,33 @@ import androidx.core.widget.doOnTextChanged import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.platform.VectorBaseActivity -import kotlinx.android.synthetic.main.activity_bug_report.* +import im.vector.app.databinding.ActivityBugReportBinding + import timber.log.Timber /** * Form to send a bug report */ -class BugReportActivity : VectorBaseActivity() { +class BugReportActivity : VectorBaseActivity() { override fun injectWith(injector: ScreenComponent) { injector.inject(this) } - override fun getLayoutRes() = R.layout.activity_bug_report + override fun getBinding() = ActivityBugReportBinding.inflate(layoutInflater) private var forSuggestion: Boolean = false override fun initUiAndData() { - configureToolbar(bugReportToolbar) + configureToolbar(views.bugReportToolbar) setupViews() if (bugReporter.screenshot != null) { - bug_report_screenshot_preview.setImageBitmap(bugReporter.screenshot) + views.bugReportScreenshotPreview.setImageBitmap(bugReporter.screenshot) } else { - bug_report_screenshot_preview.isVisible = false - bug_report_button_include_screenshot.isChecked = false - bug_report_button_include_screenshot.isEnabled = false + views.bugReportScreenshotPreview.isVisible = false + views.bugReportButtonIncludeScreenshot.isChecked = false + views.bugReportButtonIncludeScreenshot.isEnabled = false } forSuggestion = intent.getBooleanExtra("FOR_SUGGESTION", false) @@ -58,19 +60,19 @@ class BugReportActivity : VectorBaseActivity() { if (forSuggestion) { supportActionBar?.setTitle(R.string.send_suggestion) - bug_report_first_text.setText(R.string.send_suggestion_content) - bug_report_text_input_layout.hint = getString(R.string.send_suggestion_report_placeholder) + views.bugReportFirstText.setText(R.string.send_suggestion_content) + views.bugReportTextInputLayout.hint = getString(R.string.send_suggestion_report_placeholder) - bug_report_logs_description.isVisible = false + views.bugReportLogsDescription.isVisible = false - bug_report_button_include_logs.isChecked = false - bug_report_button_include_logs.isVisible = false + views.bugReportButtonIncludeLogs.isChecked = false + views.bugReportButtonIncludeLogs.isVisible = false - bug_report_button_include_crash_logs.isChecked = false - bug_report_button_include_crash_logs.isVisible = false + views.bugReportButtonIncludeCrashLogs.isChecked = false + views.bugReportButtonIncludeCrashLogs.isVisible = false - bug_report_button_include_key_share_history.isChecked = false - bug_report_button_include_key_share_history.isVisible = false + views.bugReportButtonIncludeKeyShareHistory.isChecked = false + views.bugReportButtonIncludeKeyShareHistory.isVisible = false // Keep the screenshot } else { @@ -79,15 +81,15 @@ class BugReportActivity : VectorBaseActivity() { } private fun setupViews() { - bug_report_edit_text.doOnTextChanged { _, _, _, _ -> textChanged() } - bug_report_button_include_screenshot.setOnCheckedChangeListener { _, _ -> onSendScreenshotChanged() } + views.bugReportEditText.doOnTextChanged { _, _, _, _ -> textChanged() } + views.bugReportButtonIncludeScreenshot.setOnCheckedChangeListener { _, _ -> onSendScreenshotChanged() } } override fun getMenuRes() = R.menu.bug_report override fun onPrepareOptionsMenu(menu: Menu): Boolean { menu.findItem(R.id.ic_action_send_bug_report)?.let { - val isValid = !bug_report_mask_view.isVisible + val isValid = !views.bugReportMaskView.isVisible it.isEnabled = isValid it.icon.alpha = if (isValid) 255 else 100 @@ -99,10 +101,10 @@ class BugReportActivity : VectorBaseActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.ic_action_send_bug_report -> { - if (bug_report_edit_text.text.toString().trim().length >= 10) { + if (views.bugReportEditText.text.toString().trim().length >= 10) { sendBugReport() } else { - bug_report_text_input_layout.error = getString(R.string.bug_report_error_too_short) + views.bugReportTextInputLayout.error = getString(R.string.bug_report_error_too_short) } return true } @@ -114,24 +116,24 @@ class BugReportActivity : VectorBaseActivity() { * Send the bug report */ private fun sendBugReport() { - bug_report_scrollview.alpha = 0.3f - bug_report_mask_view.isVisible = true + views.bugReportScrollview.alpha = 0.3f + views.bugReportMaskView.isVisible = true invalidateOptionsMenu() - bug_report_progress_text_view.isVisible = true - bug_report_progress_text_view.text = getString(R.string.send_bug_report_progress, "0") + views.bugReportProgressTextView.isVisible = true + views.bugReportProgressTextView.text = getString(R.string.send_bug_report_progress, "0") - bug_report_progress_view.isVisible = true - bug_report_progress_view.progress = 0 + views.bugReportProgressView.isVisible = true + views.bugReportProgressView.progress = 0 bugReporter.sendBugReport(this, forSuggestion, - bug_report_button_include_logs.isChecked, - bug_report_button_include_crash_logs.isChecked, - bug_report_button_include_key_share_history.isChecked, - bug_report_button_include_screenshot.isChecked, - bug_report_edit_text.text.toString(), + views.bugReportButtonIncludeLogs.isChecked, + views.bugReportButtonIncludeCrashLogs.isChecked, + views.bugReportButtonIncludeKeyShareHistory.isChecked, + views.bugReportButtonIncludeScreenshot.isChecked, + views.bugReportEditText.text.toString(), object : BugReporter.IMXBugReportListener { override fun onUploadFailed(reason: String?) { try { @@ -148,10 +150,10 @@ class BugReportActivity : VectorBaseActivity() { Timber.e(e, "## onUploadFailed() : failed to display the toast") } - bug_report_mask_view.isVisible = false - bug_report_progress_view.isVisible = false - bug_report_progress_text_view.isVisible = false - bug_report_scrollview.alpha = 1.0f + views.bugReportMaskView.isVisible = false + views.bugReportProgressView.isVisible = false + views.bugReportProgressTextView.isVisible = false + views.bugReportScrollview.alpha = 1.0f invalidateOptionsMenu() } @@ -163,8 +165,8 @@ class BugReportActivity : VectorBaseActivity() { override fun onProgress(progress: Int) { val myProgress = progress.coerceIn(0, 100) - bug_report_progress_view.progress = myProgress - bug_report_progress_text_view.text = getString(R.string.send_bug_report_progress, myProgress.toString()) + views.bugReportProgressView.progress = myProgress + views.bugReportProgressTextView.text = getString(R.string.send_bug_report_progress, myProgress.toString()) } override fun onUploadSucceed() { @@ -192,11 +194,11 @@ class BugReportActivity : VectorBaseActivity() { * ========================================================================================== */ private fun textChanged() { - bug_report_text_input_layout.error = null + views.bugReportTextInputLayout.error = null } - internal fun onSendScreenshotChanged() { - bug_report_screenshot_preview.isVisible = bug_report_button_include_screenshot.isChecked && bugReporter.screenshot != null + private fun onSendScreenshotChanged() { + views.bugReportScreenshotPreview.isVisible = views.bugReportButtonIncludeScreenshot.isChecked && bugReporter.screenshot != null } override fun onBackPressed() { diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiChooserFragment.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiChooserFragment.kt index af40aa970d..588c1789f1 100644 --- a/vector/src/main/java/im/vector/app/features/reactions/EmojiChooserFragment.kt +++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiChooserFragment.kt @@ -16,20 +16,26 @@ package im.vector.app.features.reactions import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.emoji_chooser_fragment.* +import im.vector.app.databinding.EmojiChooserFragmentBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject class EmojiChooserFragment @Inject constructor( private val emojiRecyclerAdapter: EmojiRecyclerAdapter -) : VectorBaseFragment(), +) : VectorBaseFragment(), EmojiRecyclerAdapter.InteractionListener, ReactionClickListener { - override fun getLayoutResId() = R.layout.emoji_chooser_fragment + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): EmojiChooserFragmentBinding { + return EmojiChooserFragmentBinding.inflate(inflater, container, false) + } private lateinit var viewModel: EmojiChooserViewModel @@ -40,7 +46,7 @@ class EmojiChooserFragment @Inject constructor( emojiRecyclerAdapter.reactionClickListener = this emojiRecyclerAdapter.interactionListener = this - emojiRecyclerView.adapter = emojiRecyclerAdapter + views.emojiRecyclerView.adapter = emojiRecyclerAdapter viewModel.moveToSection.observe(viewLifecycleOwner) { section -> emojiRecyclerAdapter.scrollToSection(section) @@ -56,7 +62,7 @@ class EmojiChooserFragment @Inject constructor( } override fun onDestroyView() { - emojiRecyclerView.cleanup() + views.emojiRecyclerView.cleanup() emojiRecyclerAdapter.reactionClickListener = null emojiRecyclerAdapter.interactionListener = null super.onDestroyView() diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt index 25cb90d3a4..1efef67d07 100644 --- a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt @@ -35,9 +35,10 @@ import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.observeEvent import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivityEmojiReactionPickerBinding import im.vector.app.features.reactions.data.EmojiDataSource import io.reactivex.android.schedulers.AndroidSchedulers -import kotlinx.android.synthetic.main.activity_emoji_reaction_picker.* + import timber.log.Timber import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -47,7 +48,7 @@ import javax.inject.Inject * TODO: Loading indicator while getting emoji data source? * TODO: Finish Refactor to vector base activity */ -class EmojiReactionPickerActivity : VectorBaseActivity(), +class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvider.FontProviderListener { private lateinit var tabLayout: TabLayout @@ -56,7 +57,7 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), override fun getMenuRes() = R.menu.menu_emoji_reaction_picker - override fun getLayoutRes() = R.layout.activity_emoji_reaction_picker + override fun getBinding() = ActivityEmojiReactionPickerBinding.inflate(layoutInflater) override fun getTitleRes() = R.string.title_activity_emoji_reaction_picker @@ -83,7 +84,7 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), } override fun initUiAndData() { - configureToolbar(emojiPickerToolbar) + configureToolbar(views.emojiPickerToolbar) emojiCompatFontProvider.let { EmojiDrawView.configureTextPaint(this, it.typeface) it.addListener(this) @@ -127,8 +128,8 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), } } - emojiPickerWholeListFragmentContainer.isVisible = true - emojiPickerFilteredListFragmentContainer.isVisible = false + views.emojiPickerWholeListFragmentContainer.isVisible = true + views.emojiPickerFilteredListFragmentContainer.isVisible = false tabLayout.isVisible = true } @@ -191,12 +192,12 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), private fun onQueryText(query: String) { if (query.isEmpty()) { tabLayout.isVisible = true - emojiPickerWholeListFragmentContainer.isVisible = true - emojiPickerFilteredListFragmentContainer.isVisible = false + views.emojiPickerWholeListFragmentContainer.isVisible = true + views.emojiPickerFilteredListFragmentContainer.isVisible = false } else { tabLayout.isVisible = false - emojiPickerWholeListFragmentContainer.isVisible = false - emojiPickerFilteredListFragmentContainer.isVisible = true + views.emojiPickerWholeListFragmentContainer.isVisible = false + views.emojiPickerFilteredListFragmentContainer.isVisible = true searchResultViewModel.handle(EmojiSearchAction.UpdateQuery(query)) } } diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultFragment.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultFragment.kt index 28df628cf1..435d19013e 100644 --- a/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultFragment.kt +++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultFragment.kt @@ -16,7 +16,9 @@ package im.vector.app.features.reactions import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -24,14 +26,17 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.LiveEvent -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject class EmojiSearchResultFragment @Inject constructor( private val epoxyController: EmojiSearchResultController -) : VectorBaseFragment(), ReactionClickListener { +) : VectorBaseFragment(), ReactionClickListener { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: EmojiSearchResultViewModel by activityViewModel() @@ -41,12 +46,12 @@ class EmojiSearchResultFragment @Inject constructor( super.onViewCreated(view, savedInstanceState) sharedViewModel = activityViewModelProvider.get(EmojiChooserViewModel::class.java) epoxyController.listener = this - genericRecyclerView.configureWith(epoxyController, showDivider = true) + views.genericRecyclerView.configureWith(epoxyController, showDivider = true) } override fun onDestroyView() { epoxyController.listener = null - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt index b180018480..44477a2b5b 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt @@ -17,8 +17,10 @@ package im.vector.app.features.roomdirectory import android.os.Bundle +import android.view.LayoutInflater import android.view.MenuItem import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import com.google.android.material.snackbar.Snackbar @@ -30,10 +32,12 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.toast +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentPublicRoomsBinding import im.vector.app.features.permalink.NavigationInterceptor import im.vector.app.features.permalink.PermalinkHandler import io.reactivex.rxkotlin.subscribeBy -import kotlinx.android.synthetic.main.fragment_public_rooms.* + import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom import timber.log.Timber @@ -48,19 +52,22 @@ class PublicRoomsFragment @Inject constructor( private val publicRoomsController: PublicRoomsController, private val permalinkHandler: PermalinkHandler, private val session: Session -) : VectorBaseFragment(), PublicRoomsController.Callback { +) : VectorBaseFragment(), + PublicRoomsController.Callback { private val viewModel: RoomDirectoryViewModel by activityViewModel() private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel - override fun getLayoutResId() = R.layout.fragment_public_rooms + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentPublicRoomsBinding { + return FragmentPublicRoomsBinding.inflate(inflater, container, false) + } override fun getMenuRes() = R.menu.menu_room_directory override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - vectorBaseActivity.setSupportActionBar(publicRoomsToolbar) + vectorBaseActivity.setSupportActionBar(views.publicRoomsToolbar) vectorBaseActivity.supportActionBar?.let { it.setDisplayShowHomeEnabled(true) @@ -70,14 +77,14 @@ class PublicRoomsFragment @Inject constructor( sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java) setupRecyclerView() - publicRoomsFilter.queryTextChanges() + views.publicRoomsFilter.queryTextChanges() .debounce(500, TimeUnit.MILLISECONDS) .subscribeBy { viewModel.handle(RoomDirectoryAction.FilterWith(it.toString())) } .disposeOnDestroyView() - publicRoomsCreateNewRoom.debouncedClicks { + views.publicRoomsCreateNewRoom.debouncedClicks { sharedActionViewModel.post(RoomDirectorySharedAction.CreateRoom) } @@ -89,7 +96,7 @@ class PublicRoomsFragment @Inject constructor( private fun handleViewEvents(viewEvents: RoomDirectoryViewEvents) { when (viewEvents) { is RoomDirectoryViewEvents.Failure -> { - Snackbar.make(publicRoomsCoordinator, errorFormatter.toHumanReadable(viewEvents.throwable), Snackbar.LENGTH_SHORT) + Snackbar.make(views.publicRoomsCoordinator, errorFormatter.toHumanReadable(viewEvents.throwable), Snackbar.LENGTH_SHORT) .show() } }.exhaustive @@ -97,7 +104,7 @@ class PublicRoomsFragment @Inject constructor( override fun onDestroyView() { publicRoomsController.callback = null - publicRoomsList.cleanup() + views.publicRoomsList.cleanup() super.onDestroyView() } @@ -113,8 +120,8 @@ class PublicRoomsFragment @Inject constructor( } private fun setupRecyclerView() { - publicRoomsList.trackItemsVisibilityChange() - publicRoomsList.configureWith(publicRoomsController) + views.publicRoomsList.trackItemsVisibilityChange() + views.publicRoomsList.configureWith(publicRoomsController) publicRoomsController.callback = this } @@ -164,9 +171,9 @@ class PublicRoomsFragment @Inject constructor( override fun invalidate() = withState(viewModel) { state -> if (!initialValueSet) { initialValueSet = true - if (publicRoomsFilter.query.toString() != state.currentFilter) { + if (views.publicRoomsFilter.query.toString() != state.currentFilter) { // For initial filter - publicRoomsFilter.setQuery(state.currentFilter, false) + views.publicRoomsFilter.setQuery(state.currentFilter, false) } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt index a21f4e670a..833be9164e 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt @@ -26,18 +26,19 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs import im.vector.app.features.roomdirectory.picker.RoomDirectoryPickerFragment import javax.inject.Inject -class RoomDirectoryActivity : VectorBaseActivity() { +class RoomDirectoryActivity : VectorBaseActivity() { @Inject lateinit var roomDirectoryViewModelFactory: RoomDirectoryViewModel.Factory private val roomDirectoryViewModel: RoomDirectoryViewModel by viewModel() private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun injectWith(injector: ScreenComponent) { injector.inject(this) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt index b6ee00a52f..58058c3a02 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt @@ -25,17 +25,18 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel /** * Simple container for [CreateRoomFragment] */ -class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable { +class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable { private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun configure(toolbar: Toolbar) { configureToolbar(toolbar) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index f859009b13..73dc94fb0d 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -19,7 +19,9 @@ package im.vector.app.features.roomdirectory.createroom import android.net.Uri import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import com.airbnb.mvrx.Loading @@ -35,11 +37,13 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider +import im.vector.app.databinding.FragmentCreateRoomBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_create_room.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import kotlinx.parcelize.Parcelize + + import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure import javax.inject.Inject @@ -52,7 +56,7 @@ class CreateRoomFragment @Inject constructor( private val createRoomController: CreateRoomController, val createRoomViewModelFactory: CreateRoomViewModel.Factory, colorProvider: ColorProvider -) : VectorBaseFragment(), +) : VectorBaseFragment(), CreateRoomController.Listener, GalleryOrCameraDialogHelper.Listener, OnBackPressed { @@ -63,15 +67,17 @@ class CreateRoomFragment @Inject constructor( private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) - override fun getLayoutResId() = R.layout.fragment_create_room + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentCreateRoomBinding { + return FragmentCreateRoomBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - vectorBaseActivity.setSupportActionBar(createRoomToolbar) + vectorBaseActivity.setSupportActionBar(views.createRoomToolbar) sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java) setupWaitingView() setupRecyclerView() - createRoomClose.debouncedClicks { + views.createRoomClose.debouncedClicks { sharedActionViewModel.post(RoomDirectorySharedAction.Back) } viewModel.observeViewEvents { @@ -90,18 +96,18 @@ class CreateRoomFragment @Inject constructor( } private fun setupWaitingView() { - waitingStatusText.isVisible = true - waitingStatusText.setText(R.string.create_room_in_progress) + views.waitingView.waitingStatusText.isVisible = true + views.waitingView.waitingStatusText.setText(R.string.create_room_in_progress) } override fun onDestroyView() { - createRoomForm.cleanup() + views.createRoomForm.cleanup() createRoomController.listener = null super.onDestroyView() } private fun setupRecyclerView() { - createRoomForm.configureWith(createRoomController) + views.createRoomForm.configureWith(createRoomController) createRoomController.listener = this } @@ -169,7 +175,7 @@ class CreateRoomFragment @Inject constructor( override fun invalidate() = withState(viewModel) { state -> val async = state.asyncCreateRoomRequest - waiting_view.isVisible = async is Loading + views.waitingView.root.isVisible = async is Loading if (async is Success) { // Navigate to freshly created room navigator.openRoom(requireActivity(), async()) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt index 4bfd60394a..d863541b23 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt @@ -17,8 +17,11 @@ package im.vector.app.features.roomdirectory.picker import android.os.Bundle +import android.view.LayoutInflater import android.view.MenuItem import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -27,11 +30,13 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding import im.vector.app.features.roomdirectory.RoomDirectoryAction import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel import im.vector.app.features.roomdirectory.RoomDirectoryViewModel -import kotlinx.android.synthetic.main.fragment_room_directory_picker.* + import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData import timber.log.Timber import javax.inject.Inject @@ -39,18 +44,21 @@ import javax.inject.Inject // TODO Menu to add custom room directory (not done in RiotWeb so far...) class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory, private val roomDirectoryPickerController: RoomDirectoryPickerController -) : VectorBaseFragment(), RoomDirectoryPickerController.Callback { +) : VectorBaseFragment(), + RoomDirectoryPickerController.Callback { private val viewModel: RoomDirectoryViewModel by activityViewModel() private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_room_directory_picker + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomDirectoryPickerBinding { + return FragmentRoomDirectoryPickerBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - vectorBaseActivity.setSupportActionBar(toolbar) + vectorBaseActivity.setSupportActionBar(views.toolbar) vectorBaseActivity.supportActionBar?.let { it.setDisplayShowHomeEnabled(true) @@ -62,7 +70,7 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie } override fun onDestroyView() { - roomDirectoryPickerList.cleanup() + views.roomDirectoryPickerList.cleanup() roomDirectoryPickerController.callback = null super.onDestroyView() } @@ -80,7 +88,7 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie } private fun setupRecyclerView() { - roomDirectoryPickerList.configureWith(roomDirectoryPickerController) + views.roomDirectoryPickerList.configureWith(roomDirectoryPickerController) roomDirectoryPickerController.callback = this } @@ -93,7 +101,7 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.select_room_directory) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.select_room_directory) } override fun retry() { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt index 3585c8bbf2..d0d617469c 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt @@ -24,7 +24,8 @@ import im.vector.app.R import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity -import kotlinx.android.parcel.Parcelize +import im.vector.app.databinding.ActivitySimpleBinding +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData import org.matrix.android.sdk.api.util.MatrixItem @@ -47,7 +48,7 @@ data class RoomPreviewData( get() = MatrixItem.RoomItem(roomId, roomName ?: roomAlias, avatarUrl) } -class RoomPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { +class RoomPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { companion object { private const val ARG = "ARG" @@ -72,7 +73,7 @@ class RoomPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { } } - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun configure(toolbar: Toolbar) { configureToolbar(toolbar) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt index bc4552fc11..577b39ca19 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.roomdirectory.roompreview import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isVisible import androidx.transition.TransitionManager import com.airbnb.mvrx.Loading @@ -29,9 +31,11 @@ import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.ButtonStateView import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentRoomPreviewNoPreviewBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomdirectory.JoinState -import kotlinx.android.synthetic.main.fragment_room_preview_no_preview.* + import org.matrix.android.sdk.api.util.MatrixItem import javax.inject.Inject @@ -41,12 +45,14 @@ import javax.inject.Inject class RoomPreviewNoPreviewFragment @Inject constructor( val roomPreviewViewModelFactory: RoomPreviewViewModel.Factory, private val avatarRenderer: AvatarRenderer -) : VectorBaseFragment() { +) : VectorBaseFragment() { private val roomPreviewViewModel: RoomPreviewViewModel by fragmentViewModel() private val roomPreviewData: RoomPreviewData by args() - override fun getLayoutResId() = R.layout.fragment_room_preview_no_preview + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomPreviewNoPreviewBinding { + return FragmentRoomPreviewNoPreviewBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt index e994a3c3ec..29a8fb31cd 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -19,8 +19,10 @@ package im.vector.app.features.roommemberprofile import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.MenuItem import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import com.airbnb.mvrx.Fail @@ -41,15 +43,17 @@ import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.startSharePlainTextIntent +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.features.crypto.verification.VerificationBottomSheet import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailPendingAction import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_matrix_profile.* -import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.* +import kotlinx.parcelize.Parcelize + + import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.util.MatrixItem import javax.inject.Inject @@ -65,14 +69,17 @@ class RoomMemberProfileFragment @Inject constructor( private val roomMemberProfileController: RoomMemberProfileController, private val avatarRenderer: AvatarRenderer, private val roomDetailPendingActionStore: RoomDetailPendingActionStore -) : VectorBaseFragment(), RoomMemberProfileController.Callback { +) : VectorBaseFragment(), + RoomMemberProfileController.Callback { private val fragmentArgs: RoomMemberProfileArgs by args() private val viewModel: RoomMemberProfileViewModel by fragmentViewModel() private var appBarStateChangeListener: AppBarStateChangeListener? = null - override fun getLayoutResId() = R.layout.fragment_matrix_profile + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentMatrixProfileBinding { + return FragmentMatrixProfileBinding.inflate(inflater, container, false) + } override fun getMenuRes() = R.menu.vector_room_member_profile diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt index 323e25a022..191a30724f 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt @@ -20,7 +20,9 @@ import android.content.DialogInterface import android.os.Bundle import android.os.Parcelable import android.view.KeyEvent +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.fragment.app.Fragment import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel @@ -30,14 +32,19 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetWithFragmentsBinding import im.vector.app.features.crypto.verification.VerificationBottomSheet -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import javax.inject.Inject import kotlin.reflect.KClass -class DeviceListBottomSheet : VectorBaseBottomSheetDialogFragment() { +class DeviceListBottomSheet : + VectorBaseBottomSheetDialogFragment() { - override fun getLayoutResId() = R.layout.bottom_sheet_with_fragments + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetWithFragmentsBinding { + return BottomSheetWithFragmentsBinding.inflate(inflater, container, false) + } private val viewModel: DeviceListBottomSheetViewModel by fragmentViewModel(DeviceListBottomSheetViewModel::class) diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt index 342213fac0..608d3cd209 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.roommemberprofile.devices import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -25,23 +27,28 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter -import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import javax.inject.Inject class DeviceListFragment @Inject constructor( val dimensionConverter: DimensionConverter, val epoxyController: DeviceListEpoxyController -) : VectorBaseFragment(), DeviceListEpoxyController.InteractionListener { +) : VectorBaseFragment(), + DeviceListEpoxyController.InteractionListener { - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding { + return BottomSheetGenericListBinding.inflate(inflater, container, false) + } private val viewModel: DeviceListBottomSheetViewModel by parentFragmentViewModel(DeviceListBottomSheetViewModel::class) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bottomSheetRecyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) - bottomSheetRecyclerView.configureWith( + views.bottomSheetRecyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) + views.bottomSheetRecyclerView.configureWith( epoxyController, showDivider = false, hasFixedSize = false) @@ -49,7 +56,7 @@ class DeviceListFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt index 1b5e571519..b153645976 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceTrustInfoActionFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.roommemberprofile.devices import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -25,23 +27,28 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter -import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import javax.inject.Inject class DeviceTrustInfoActionFragment @Inject constructor( val dimensionConverter: DimensionConverter, val epoxyController: DeviceTrustInfoEpoxyController -) : VectorBaseFragment(), DeviceTrustInfoEpoxyController.InteractionListener { +) : VectorBaseFragment(), + DeviceTrustInfoEpoxyController.InteractionListener { - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding { + return BottomSheetGenericListBinding.inflate(inflater, container, false) + } private val viewModel: DeviceListBottomSheetViewModel by parentFragmentViewModel(DeviceListBottomSheetViewModel::class) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bottomSheetRecyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) - bottomSheetRecyclerView.configureWith( + views.bottomSheetRecyclerView.setPadding(0, dimensionConverter.dpToPx(16), 0, dimensionConverter.dpToPx(16)) + views.bottomSheetRecyclerView.configureWith( epoxyController, showDivider = false, hasFixedSize = false) @@ -49,7 +56,7 @@ class DeviceTrustInfoActionFragment @Inject constructor( } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt index eee0cc4081..b0dbdacd49 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt @@ -23,7 +23,7 @@ import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.extensions.hideKeyboard -import kotlinx.android.synthetic.main.dialog_edit_power_level.view.* + import org.matrix.android.sdk.api.session.room.powerlevels.Role object EditPowerLevelDialogs { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 628e3869b4..2199cb7211 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -19,8 +19,10 @@ package im.vector.app.features.roomprofile import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.MenuItem import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.app.ActivityOptionsCompat import androidx.core.content.pm.ShortcutManagerCompat @@ -40,6 +42,8 @@ import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.startSharePlainTextIntent +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.features.crypto.util.toImageRes import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.list.actions.RoomListActionsArgs @@ -47,10 +51,10 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomS import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.media.BigImageViewerActivity -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_matrix_profile.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* -import kotlinx.android.synthetic.main.view_stub_room_profile_header.* +import kotlinx.parcelize.Parcelize + + + import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem @@ -66,7 +70,7 @@ class RoomProfileFragment @Inject constructor( private val roomProfileController: RoomProfileController, private val avatarRenderer: AvatarRenderer, val roomProfileViewModelFactory: RoomProfileViewModel.Factory -) : VectorBaseFragment(), +) : VectorBaseFragment(), RoomProfileController.Callback { private val roomProfileArgs: RoomProfileArgs by args() @@ -76,7 +80,9 @@ class RoomProfileFragment @Inject constructor( private var appBarStateChangeListener: AppBarStateChangeListener? = null - override fun getLayoutResId() = R.layout.fragment_matrix_profile + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentMatrixProfileBinding { + return FragmentMatrixProfileBinding.inflate(inflater, container, false) + } override fun getMenuRes() = R.menu.vector_room_profile diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt index 689b057385..0edc985ebe 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.roomprofile.alias import android.content.DialogInterface import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import com.airbnb.mvrx.args @@ -32,13 +34,15 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.shareText import im.vector.app.core.utils.toast +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomprofile.RoomProfileArgs import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheet import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheetSharedAction import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheetSharedActionViewModel -import kotlinx.android.synthetic.main.fragment_room_setting_generic.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* + + import org.matrix.android.sdk.api.session.room.alias.RoomAliasError import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.util.toMatrixItem @@ -49,7 +53,7 @@ class RoomAliasFragment @Inject constructor( private val controller: RoomAliasController, private val avatarRenderer: AvatarRenderer ) : - VectorBaseFragment(), + VectorBaseFragment(), RoomAliasController.Callback { private val viewModel: RoomAliasViewModel by fragmentViewModel() @@ -57,17 +61,19 @@ class RoomAliasFragment @Inject constructor( private val roomProfileArgs: RoomProfileArgs by args() - override fun getLayoutResId() = R.layout.fragment_room_setting_generic + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding { + return FragmentRoomSettingGenericBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(RoomAliasBottomSheetSharedActionViewModel::class.java) controller.callback = this - setupToolbar(roomSettingsToolbar) - roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) - waitingStatusText.setText(R.string.please_wait) - waitingStatusText.isVisible = true + setupToolbar(views.roomSettingsToolbar) + views.roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) + views.waitingView.waitingStatusText.setText(R.string.please_wait) + views.waitingView.waitingStatusText.isVisible = true viewModel.observeViewEvents { when (it) { @@ -110,20 +116,20 @@ class RoomAliasFragment @Inject constructor( override fun onDestroyView() { controller.callback = null - roomSettingsRecyclerView.cleanup() + views.roomSettingsRecyclerView.cleanup() super.onDestroyView() } override fun invalidate() = withState(viewModel) { state -> - waiting_view.isVisible = state.isLoading + views.waitingView.root.isVisible = state.isLoading controller.setData(state) renderRoomSummary(state) } private fun renderRoomSummary(state: RoomAliasViewState) { state.roomSummary()?.let { - roomSettingsToolbarTitleView.text = it.displayName - avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView) + views.roomSettingsToolbarTitleView.text = it.displayName + avatarRenderer.render(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView) } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt index 265abe5862..6e6af86e66 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt @@ -18,7 +18,9 @@ package im.vector.app.features.roomprofile.alias.detail import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -27,8 +29,9 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_generic_list.* +import im.vector.app.databinding.BottomSheetGenericListBinding +import kotlinx.parcelize.Parcelize + import javax.inject.Inject @Parcelize @@ -43,7 +46,9 @@ data class RoomAliasBottomSheetArgs( /** * Bottom sheet fragment that shows room alias information with list of contextual actions */ -class RoomAliasBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomAliasBottomSheetController.Listener { +class RoomAliasBottomSheet : + VectorBaseBottomSheetDialogFragment(), + RoomAliasBottomSheetController.Listener { private lateinit var sharedActionViewModel: RoomAliasBottomSheetSharedActionViewModel @Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool @@ -58,17 +63,19 @@ class RoomAliasBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomAliasBot injector.inject(this) } - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding { + return BottomSheetGenericListBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(RoomAliasBottomSheetSharedActionViewModel::class.java) - bottomSheetRecyclerView.configureWith(controller, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) + views.bottomSheetRecyclerView.configureWith(controller, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true) controller.listener = this } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() controller.listener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt index 349321c87a..556d950230 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.roomprofile.banned import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.SearchView import androidx.core.view.isVisible @@ -29,9 +31,10 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.toast +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomprofile.RoomProfileArgs -import kotlinx.android.synthetic.main.fragment_room_setting_generic.* + import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject @@ -40,12 +43,15 @@ class RoomBannedMemberListFragment @Inject constructor( val viewModelFactory: RoomBannedMemberListViewModel.Factory, private val roomMemberListController: RoomBannedMemberListController, private val avatarRenderer: AvatarRenderer -) : VectorBaseFragment(), RoomBannedMemberListController.Callback { +) : VectorBaseFragment(), + RoomBannedMemberListController.Callback { private val viewModel: RoomBannedMemberListViewModel by fragmentViewModel() private val roomProfileArgs: RoomProfileArgs by args() - override fun getLayoutResId() = R.layout.fragment_room_setting_generic + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding { + return FragmentRoomSettingGenericBinding.inflate(inflater, container, false) + } override fun onUnbanClicked(roomMember: RoomMemberSummary) { viewModel.handle(RoomBannedMemberListAction.QueryInfo(roomMember)) @@ -54,9 +60,9 @@ class RoomBannedMemberListFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) roomMemberListController.callback = this - setupToolbar(roomSettingsToolbar) + setupToolbar(views.roomSettingsToolbar) setupSearchView() - roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true) + views.roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true) viewModel.observeViewEvents { when (it) { @@ -83,14 +89,14 @@ class RoomBannedMemberListFragment @Inject constructor( } override fun onDestroyView() { - roomSettingsRecyclerView.cleanup() + views.roomSettingsRecyclerView.cleanup() super.onDestroyView() } private fun setupSearchView() { - searchViewAppBarLayout.isVisible = true - searchView.queryHint = getString(R.string.search_banned_user_hint) - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + views.searchViewAppBarLayout.isVisible = true + views.searchView.queryHint = getString(R.string.search_banned_user_hint) + views.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { return true } @@ -109,8 +115,8 @@ class RoomBannedMemberListFragment @Inject constructor( private fun renderRoomSummary(state: RoomBannedMemberListViewState) { state.roomSummary()?.let { - roomSettingsToolbarTitleView.text = it.displayName - avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView) + views.roomSettingsToolbarTitleView.text = it.displayName + avatarRenderer.render(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView) } } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt index fb42b8ce27..62fb9e2b02 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.roomprofile.members import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.SearchView import androidx.core.view.isVisible @@ -29,10 +31,12 @@ import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentRoomMemberListBinding +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomprofile.RoomProfileArgs -import kotlinx.android.synthetic.main.fragment_room_member_list.* -import kotlinx.android.synthetic.main.fragment_room_setting_generic.* + + import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary @@ -44,12 +48,15 @@ class RoomMemberListFragment @Inject constructor( val viewModelFactory: RoomMemberListViewModel.Factory, private val roomMemberListController: RoomMemberListController, private val avatarRenderer: AvatarRenderer -) : VectorBaseFragment(), RoomMemberListController.Callback { +) : VectorBaseFragment(), + RoomMemberListController.Callback { private val viewModel: RoomMemberListViewModel by fragmentViewModel() private val roomProfileArgs: RoomProfileArgs by args() - override fun getLayoutResId() = R.layout.fragment_room_member_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomMemberListBinding { + return FragmentRoomMemberListBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -57,7 +64,7 @@ class RoomMemberListFragment @Inject constructor( setupToolbar(roomSettingsToolbar) setupSearchView() setupInviteUsersButton() - roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true) + views.roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true) } private fun setupInviteUsersButton() { @@ -65,7 +72,7 @@ class RoomMemberListFragment @Inject constructor( navigator.openInviteUsersToRoom(requireContext(), roomProfileArgs.roomId) } // Hide FAB when list is scrolling - roomSettingsRecyclerView.addOnScrollListener( + views.roomSettingsRecyclerView.addOnScrollListener( object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { when (newState) { @@ -99,7 +106,7 @@ class RoomMemberListFragment @Inject constructor( } override fun onDestroyView() { - roomSettingsRecyclerView.cleanup() + views.roomSettingsRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index d66599db91..17689c3dfb 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -18,9 +18,11 @@ package im.vector.app.features.roomprofile.settings import android.net.Uri import android.os.Bundle +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import com.airbnb.mvrx.args @@ -36,6 +38,7 @@ import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.toast +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomprofile.RoomProfileArgs import im.vector.app.features.roomprofile.RoomProfileSharedAction @@ -44,8 +47,8 @@ import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistory import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistoryVisibilityBottomSheet import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleBottomSheet import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel -import kotlinx.android.synthetic.main.fragment_room_setting_generic.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* + + import org.matrix.android.sdk.api.util.toMatrixItem import java.util.UUID import javax.inject.Inject @@ -56,7 +59,7 @@ class RoomSettingsFragment @Inject constructor( colorProvider: ColorProvider, private val avatarRenderer: AvatarRenderer ) : - VectorBaseFragment(), + VectorBaseFragment(), RoomSettingsController.Callback, OnBackPressed, GalleryOrCameraDialogHelper.Listener { @@ -69,7 +72,9 @@ class RoomSettingsFragment @Inject constructor( private val roomProfileArgs: RoomProfileArgs by args() private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) - override fun getLayoutResId() = R.layout.fragment_room_setting_generic + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding { + return FragmentRoomSettingGenericBinding.inflate(inflater, container, false) + } override fun getMenuRes() = R.menu.vector_room_settings @@ -79,10 +84,10 @@ class RoomSettingsFragment @Inject constructor( setupRoomHistoryVisibilitySharedActionViewModel() setupRoomJoinRuleSharedActionViewModel() controller.callback = this - setupToolbar(roomSettingsToolbar) - roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) - waitingStatusText.setText(R.string.please_wait) - waitingStatusText.isVisible = true + setupToolbar(views.roomSettingsToolbar) + views.roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) + views.waitingView.waitingStatusText.setText(R.string.please_wait) + views.waitingView.waitingStatusText.isVisible = true viewModel.observeViewEvents { when (it) { @@ -122,7 +127,7 @@ class RoomSettingsFragment @Inject constructor( override fun onDestroyView() { controller.callback = null - roomSettingsRecyclerView.cleanup() + views.roomSettingsRecyclerView.cleanup() super.onDestroyView() } @@ -146,11 +151,11 @@ class RoomSettingsFragment @Inject constructor( } private fun renderRoomSummary(state: RoomSettingsViewState) { - waiting_view.isVisible = state.isLoading + views.waitingView.root.isVisible = state.isLoading state.roomSummary()?.let { - roomSettingsToolbarTitleView.text = it.displayName - avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView) + views.roomSettingsToolbarTitleView.text = it.displayName + avatarRenderer.render(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView) } invalidateOptionsMenu() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt index c12dc621a9..76d7115f30 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt @@ -24,7 +24,7 @@ import com.airbnb.mvrx.withState import im.vector.app.core.di.ScreenComponent import im.vector.app.core.ui.bottomsheet.BottomSheetGeneric import im.vector.app.core.ui.bottomsheet.BottomSheetGenericController -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt index 66c6be6086..c6cb676e1f 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt @@ -24,7 +24,7 @@ import com.airbnb.mvrx.withState import im.vector.app.core.di.ScreenComponent import im.vector.app.core.ui.bottomsheet.BottomSheetGeneric import im.vector.app.core.ui.bottomsheet.BottomSheetGenericController -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt index fb53d91e09..c86f58935e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt @@ -17,11 +17,14 @@ package im.vector.app.features.roomprofile.uploads import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.net.toUri import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState +import com.google.android.material.appbar.AppBarLayout import com.google.android.material.tabs.TabLayoutMediator import im.vector.app.R import im.vector.app.core.extensions.exhaustive @@ -29,10 +32,12 @@ import im.vector.app.core.intent.getMimeTypeFromUri import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.saveMedia import im.vector.app.core.utils.shareMedia +import im.vector.app.databinding.FragmentRoomSettingGenericBinding +import im.vector.app.databinding.FragmentRoomUploadsBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.roomprofile.RoomProfileArgs -import kotlinx.android.synthetic.main.fragment_room_uploads.* + import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject @@ -40,28 +45,31 @@ class RoomUploadsFragment @Inject constructor( private val viewModelFactory: RoomUploadsViewModel.Factory, private val avatarRenderer: AvatarRenderer, private val notificationUtils: NotificationUtils -) : VectorBaseFragment(), RoomUploadsViewModel.Factory by viewModelFactory { +) : VectorBaseFragment(), + RoomUploadsViewModel.Factory by viewModelFactory { private val roomProfileArgs: RoomProfileArgs by args() private val viewModel: RoomUploadsViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_room_uploads + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomUploadsBinding { + return FragmentRoomUploadsBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val sectionsPagerAdapter = RoomUploadsPagerAdapter(this) - roomUploadsViewPager.adapter = sectionsPagerAdapter + views.roomUploadsViewPager.adapter = sectionsPagerAdapter - TabLayoutMediator(roomUploadsTabs, roomUploadsViewPager) { tab, position -> + TabLayoutMediator(views.roomUploadsTabs, views.roomUploadsViewPager) { tab, position -> when (position) { 0 -> tab.text = getString(R.string.uploads_media_title) 1 -> tab.text = getString(R.string.uploads_files_title) } }.attach() - setupToolbar(roomUploadsToolbar) + setupToolbar(views.roomUploadsToolbar) viewModel.observeViewEvents { when (it) { @@ -88,8 +96,11 @@ class RoomUploadsFragment @Inject constructor( private fun renderRoomSummary(state: RoomUploadsViewState) { state.roomSummary()?.let { - roomUploadsToolbarTitleView.text = it.displayName - avatarRenderer.render(it.toMatrixItem(), roomUploadsToolbarAvatarImageView) + views.roomUploadsToolbarTitleView.text = it.displayName + avatarRenderer.render(it.toMatrixItem(), views.roomUploadsToolbarAvatarImageView) } } + + val roomUploadsAppBar: AppBarLayout + get() = views.roomUploadsAppBar } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/RoomUploadsFilesFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/RoomUploadsFilesFragment.kt index 3c52f2e107..591904c6f4 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/RoomUploadsFilesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/files/RoomUploadsFilesFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.roomprofile.uploads.files import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.content.ContextCompat import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading @@ -30,36 +32,40 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentGenericStateViewRecyclerBinding +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.roomprofile.uploads.RoomUploadsAction import im.vector.app.features.roomprofile.uploads.RoomUploadsViewModel -import kotlinx.android.synthetic.main.fragment_generic_state_view_recycler.* + import org.matrix.android.sdk.api.session.room.uploads.UploadEvent import javax.inject.Inject class RoomUploadsFilesFragment @Inject constructor( private val controller: UploadsFileController -) : VectorBaseFragment(), +) : VectorBaseFragment(), UploadsFileController.Listener, StateView.EventCallback { private val uploadsViewModel by parentFragmentViewModel(RoomUploadsViewModel::class) - override fun getLayoutResId() = R.layout.fragment_generic_state_view_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericStateViewRecyclerBinding { + return FragmentGenericStateViewRecyclerBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericStateViewListStateView.contentView = genericStateViewListRecycler - genericStateViewListStateView.eventCallback = this + views.genericStateViewListStateView.contentView = views.genericStateViewListRecycler + views.genericStateViewListStateView.eventCallback = this - genericStateViewListRecycler.trackItemsVisibilityChange() - genericStateViewListRecycler.configureWith(controller, showDivider = true) + views.genericStateViewListRecycler.trackItemsVisibilityChange() + views.genericStateViewListRecycler.configureWith(controller, showDivider = true) controller.listener = this } override fun onDestroyView() { super.onDestroyView() - genericStateViewListRecycler.cleanup() + views.genericStateViewListRecycler.cleanup() controller.listener = null } @@ -88,17 +94,17 @@ class RoomUploadsFilesFragment @Inject constructor( if (state.fileEvents.isEmpty()) { when (state.asyncEventsRequest) { is Loading -> { - genericStateViewListStateView.state = StateView.State.Loading + views.genericStateViewListStateView.state = StateView.State.Loading } is Fail -> { - genericStateViewListStateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncEventsRequest.error)) + views.genericStateViewListStateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncEventsRequest.error)) } is Success -> { if (state.hasMore) { // We need to load more items loadMore() } else { - genericStateViewListStateView.state = StateView.State.Empty( + views.genericStateViewListStateView.state = StateView.State.Empty( title = getString(R.string.uploads_files_no_result), image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_file) ) @@ -106,7 +112,7 @@ class RoomUploadsFilesFragment @Inject constructor( } } } else { - genericStateViewListStateView.state = StateView.State.Content + views.genericStateViewListStateView.state = StateView.State.Content controller.setData(state) } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt index d25277d9f5..32c8f8b470 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.roomprofile.uploads.media import android.os.Bundle import android.util.DisplayMetrics +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.core.util.Pair import androidx.core.view.ViewCompat @@ -35,6 +37,8 @@ import im.vector.app.core.extensions.trackItemsVisibilityChange import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter +import im.vector.app.databinding.FragmentGenericStateViewRecyclerBinding +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.media.AttachmentData import im.vector.app.features.media.ImageContentRenderer import im.vector.app.features.media.VideoContentRenderer @@ -42,8 +46,8 @@ import im.vector.app.features.roomprofile.uploads.RoomUploadsAction import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment import im.vector.app.features.roomprofile.uploads.RoomUploadsViewModel import im.vector.app.features.roomprofile.uploads.RoomUploadsViewState -import kotlinx.android.synthetic.main.fragment_generic_state_view_recycler.* -import kotlinx.android.synthetic.main.fragment_room_uploads.* + + import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent import org.matrix.android.sdk.api.session.room.model.message.getFileUrl @@ -53,24 +57,25 @@ import javax.inject.Inject class RoomUploadsMediaFragment @Inject constructor( private val controller: UploadsMediaController, private val dimensionConverter: DimensionConverter -) : VectorBaseFragment(), +) : VectorBaseFragment(), UploadsMediaController.Listener, StateView.EventCallback { private val uploadsViewModel by parentFragmentViewModel(RoomUploadsViewModel::class) - override fun getLayoutResId() = R.layout.fragment_generic_state_view_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericStateViewRecyclerBinding { + return FragmentGenericStateViewRecyclerBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericStateViewListStateView.contentView = genericStateViewListRecycler - genericStateViewListStateView.eventCallback = this - - genericStateViewListRecycler.trackItemsVisibilityChange() - genericStateViewListRecycler.layoutManager = GridLayoutManager(context, getNumberOfColumns()) - genericStateViewListRecycler.adapter = controller.adapter - genericStateViewListRecycler.setHasFixedSize(true) + views.genericStateViewListStateView.contentView = views.genericStateViewListRecycler + views.genericStateViewListStateView.eventCallback = this + views.genericStateViewListRecycler.trackItemsVisibilityChange() + views.genericStateViewListRecycler.layoutManager = GridLayoutManager(context, getNumberOfColumns()) + views.genericStateViewListRecycler.adapter = controller.adapter + views.genericStateViewListRecycler.setHasFixedSize(true) controller.listener = this } @@ -83,7 +88,7 @@ class RoomUploadsMediaFragment @Inject constructor( override fun onDestroyView() { super.onDestroyView() - genericStateViewListRecycler.cleanup() + views.genericStateViewListRecycler.cleanup() controller.listener = null } @@ -181,17 +186,17 @@ class RoomUploadsMediaFragment @Inject constructor( if (state.mediaEvents.isEmpty()) { when (state.asyncEventsRequest) { is Loading -> { - genericStateViewListStateView.state = StateView.State.Loading + views.genericStateViewListStateView.state = StateView.State.Loading } is Fail -> { - genericStateViewListStateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncEventsRequest.error)) + views.genericStateViewListStateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncEventsRequest.error)) } is Success -> { if (state.hasMore) { // We need to load more items loadMore() } else { - genericStateViewListStateView.state = StateView.State.Empty( + views.genericStateViewListStateView.state = StateView.State.Empty( title = getString(R.string.uploads_media_no_result), image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_image) ) @@ -199,7 +204,7 @@ class RoomUploadsMediaFragment @Inject constructor( } } } else { - genericStateViewListStateView.state = StateView.State.Content + views.genericStateViewListStateView.state = StateView.State.Content controller.setData(state) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt index 28702940ee..0581f06c13 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt @@ -25,8 +25,9 @@ import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivityVectorSettingsBinding import im.vector.app.features.settings.devices.VectorSettingsDevicesFragment -import kotlinx.android.synthetic.main.activity_vector_settings.* + import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.session.Session import timber.log.Timber @@ -35,12 +36,12 @@ import javax.inject.Inject /** * Displays the client settings. */ -class VectorSettingsActivity : VectorBaseActivity(), +class VectorSettingsActivity : VectorBaseActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback, FragmentManager.OnBackStackChangedListener, VectorSettingsFragmentInteractionListener { - override fun getLayoutRes() = R.layout.activity_vector_settings + override fun getBinding() = ActivityVectorSettingsBinding.inflate(layoutInflater) override fun getTitleRes() = R.string.title_activity_settings @@ -55,7 +56,7 @@ class VectorSettingsActivity : VectorBaseActivity(), } override fun initUiAndData() { - configureToolbar(settingsToolbar) + configureToolbar(views.settingsToolbar) if (isFirstCreation()) { // display the fragment diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt index add6fba38c..232ea063a8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt @@ -35,8 +35,8 @@ import timber.log.Timber abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), HasScreenInjector { - val vectorActivity: VectorBaseActivity by lazy { - activity as VectorBaseActivity + val vectorActivity: VectorBaseActivity<*> by lazy { + activity as VectorBaseActivity<*> } private var mLoadingView: View? = null diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt index c458d6a74c..e6f92e1eea 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt @@ -21,7 +21,9 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -31,12 +33,14 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentRoomSettingGenericBinding +import im.vector.app.databinding.FragmentSettingsNotificationsTroubleshootBinding import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.rageshake.BugReporter import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TroubleshootTest import im.vector.app.push.fcm.NotificationTroubleshootTestManagerFactory -import kotlinx.android.synthetic.main.fragment_settings_notifications_troubleshoot.* + import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject @@ -44,12 +48,14 @@ import javax.inject.Inject class VectorSettingsNotificationsTroubleshootFragment @Inject constructor( private val bugReporter: BugReporter, private val testManagerFactory: NotificationTroubleshootTestManagerFactory -) : VectorBaseFragment() { +) : VectorBaseFragment() { private var testManager: NotificationTroubleshootTestManager? = null // members - override fun getLayoutResId() = R.layout.fragment_settings_notifications_troubleshoot + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSettingsNotificationsTroubleshootBinding { + return FragmentSettingsNotificationsTroubleshootBinding.inflate(inflater, container, false) + } private var interactionListener: VectorSettingsFragmentInteractionListener? = null @@ -143,7 +149,7 @@ class VectorSettingsNotificationsTroubleshootFragment @Inject constructor( override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_notification_troubleshoot) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_notification_troubleshoot) tryOrNull("Unable to register the receiver") { LocalBroadcastManager.getInstance(requireContext()) diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt index e48ab337d6..8449215a09 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.settings.account.deactivation import android.content.Context import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.jakewharton.rxbinding3.widget.textChanges @@ -27,23 +29,27 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentDeactivateAccountBinding +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs import im.vector.app.features.settings.VectorSettingsActivity -import kotlinx.android.synthetic.main.fragment_deactivate_account.* + import javax.inject.Inject class DeactivateAccountFragment @Inject constructor( val viewModelFactory: DeactivateAccountViewModel.Factory -) : VectorBaseFragment() { +) : VectorBaseFragment() { private val viewModel: DeactivateAccountViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_deactivate_account + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDeactivateAccountBinding { + return FragmentDeactivateAccountBinding.inflate(inflater, container, false) + } override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.deactivate_account_title) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.deactivate_account_title) } private var settingsActivity: VectorSettingsActivity? = null diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt index f21ec2e8f4..fbfe869ecd 100644 --- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt @@ -16,8 +16,11 @@ package im.vector.app.features.settings.crosssigning import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -26,7 +29,9 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentRoomSettingGenericBinding + import javax.inject.Inject /** @@ -35,9 +40,12 @@ import javax.inject.Inject class CrossSigningSettingsFragment @Inject constructor( private val controller: CrossSigningSettingsController, val viewModelFactory: CrossSigningSettingsViewModel.Factory -) : VectorBaseFragment(), CrossSigningSettingsController.InteractionListener { +) : VectorBaseFragment(), + CrossSigningSettingsController.InteractionListener { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: CrossSigningSettingsViewModel by fragmentViewModel() @@ -60,7 +68,7 @@ class CrossSigningSettingsFragment @Inject constructor( override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.encryption_information_cross_signing_state) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.encryption_information_cross_signing_state) } override fun invalidate() = withState(viewModel) { state -> @@ -68,12 +76,12 @@ class CrossSigningSettingsFragment @Inject constructor( } private fun setupRecyclerView() { - genericRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) + views.genericRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true) controller.interactionListener = this } override fun onDestroyView() { - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() controller.interactionListener = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt index 7cc25170cb..c93d6d5652 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt @@ -17,7 +17,9 @@ package im.vector.app.features.settings.devices import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isVisible import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.fragmentViewModel @@ -28,8 +30,10 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.* +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding +import kotlinx.parcelize.Parcelize + import javax.inject.Inject @Parcelize @@ -38,7 +42,9 @@ data class DeviceVerificationInfoArgs( val deviceId: String ) : Parcelable -class DeviceVerificationInfoBottomSheet : VectorBaseBottomSheetDialogFragment(), DeviceVerificationInfoBottomSheetController.Callback { +class DeviceVerificationInfoBottomSheet : + VectorBaseBottomSheetDialogFragment(), + DeviceVerificationInfoBottomSheetController.Callback { private val viewModel: DeviceVerificationInfoBottomSheetViewModel by fragmentViewModel(DeviceVerificationInfoBottomSheetViewModel::class) @@ -52,20 +58,22 @@ class DeviceVerificationInfoBottomSheet : VectorBaseBottomSheetDialogFragment(), @Inject lateinit var controller: DeviceVerificationInfoBottomSheetController - override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding { + return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - bottomSheetRecyclerView.configureWith( + views.bottomSheetRecyclerView.configureWith( controller, showDivider = false, hasFixedSize = false) controller.callback = this - bottomSheetTitle.isVisible = false + views.bottomSheetTitle.isVisible = false } override fun onDestroyView() { - bottomSheetRecyclerView.cleanup() + views.bottomSheetRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt index 520a63d1a9..904024d031 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt @@ -17,9 +17,12 @@ package im.vector.app.features.settings.devices import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.EditText import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import com.airbnb.mvrx.Async import com.airbnb.mvrx.Loading @@ -33,9 +36,11 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.crypto.verification.VerificationBottomSheet -import kotlinx.android.synthetic.main.fragment_generic_recycler.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* + + import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import javax.inject.Inject @@ -45,23 +50,26 @@ import javax.inject.Inject class VectorSettingsDevicesFragment @Inject constructor( val devicesViewModelFactory: DevicesViewModel.Factory, private val devicesController: DevicesController -) : VectorBaseFragment(), DevicesController.Callback { +) : VectorBaseFragment(), + DevicesController.Callback { // used to avoid requesting to enter the password for each deletion // Note: Sonar does not like to use password for member name. private var mAccountPass: String = "" - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: DevicesViewModel by fragmentViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - waitingStatusText.setText(R.string.please_wait) - waitingStatusText.isVisible = true + views.waitingView.waitingStatusText.setText(R.string.please_wait) + views.waitingView.waitingStatusText.isVisible = true devicesController.callback = this - genericRecyclerView.configureWith(devicesController, showDivider = true) + views.genericRecyclerView.configureWith(devicesController, showDivider = true) viewModel.observeViewEvents { when (it) { is DevicesViewEvents.Loading -> showLoading(it.message) @@ -97,13 +105,13 @@ class VectorSettingsDevicesFragment @Inject constructor( override fun onDestroyView() { devicesController.callback = null - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() super.onDestroyView() } override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_active_sessions_manage) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_active_sessions_manage) viewModel.handle(DevicesAction.Refresh) } @@ -171,9 +179,9 @@ class VectorSettingsDevicesFragment @Inject constructor( } private fun handleRequestStatus(unIgnoreRequest: Async) { - when (unIgnoreRequest) { - is Loading -> waiting_view.isVisible = true - else -> waiting_view.isVisible = false + views.waitingView.root.isVisible = when (unIgnoreRequest) { + is Loading -> true + else -> false } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt index 40b910c1ab..3f3a2283b8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt @@ -18,8 +18,11 @@ package im.vector.app.features.settings.devtools import android.content.DialogInterface import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -30,7 +33,8 @@ import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.createJSonViewerStyleProvider -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import org.billcarsonfr.jsonviewer.JSonViewerDialog import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent import org.matrix.android.sdk.internal.di.MoshiProvider @@ -40,15 +44,18 @@ class AccountDataFragment @Inject constructor( val viewModelFactory: AccountDataViewModel.Factory, private val epoxyController: AccountDataEpoxyController, private val colorProvider: ColorProvider -) : VectorBaseFragment(), AccountDataEpoxyController.InteractionListener { +) : VectorBaseFragment(), + AccountDataEpoxyController.InteractionListener { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: AccountDataViewModel by fragmentViewModel(AccountDataViewModel::class) override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_account_data) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_account_data) } override fun invalidate() = withState(viewModel) { state -> @@ -57,13 +64,13 @@ class AccountDataFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericRecyclerView.configureWith(epoxyController, showDivider = true) + views.genericRecyclerView.configureWith(epoxyController, showDivider = true) epoxyController.interactionListener = this } override fun onDestroyView() { super.onDestroyView() - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() epoxyController.interactionListener = null } diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt index af8881ba92..8ac692025f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.settings.devtools import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -26,7 +28,8 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.createJSonViewerStyleProvider -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import org.billcarsonfr.jsonviewer.JSonViewerDialog import org.matrix.android.sdk.api.session.events.model.Event import javax.inject.Inject @@ -35,9 +38,12 @@ class GossipingEventsPaperTrailFragment @Inject constructor( val viewModelFactory: GossipingEventsPaperTrailViewModel.Factory, private val epoxyController: GossipingTrailPagedEpoxyController, private val colorProvider: ColorProvider -) : VectorBaseFragment(), GossipingTrailPagedEpoxyController.InteractionListener { +) : VectorBaseFragment(), + GossipingTrailPagedEpoxyController.InteractionListener { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: GossipingEventsPaperTrailViewModel by fragmentViewModel(GossipingEventsPaperTrailViewModel::class) @@ -50,13 +56,13 @@ class GossipingEventsPaperTrailFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericRecyclerView.configureWith(epoxyController, showDivider = true) + views.genericRecyclerView.configureWith(epoxyController, showDivider = true) epoxyController.interactionListener = this } override fun onDestroyView() { super.onDestroyView() - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() epoxyController.interactionListener = null } diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt index 6e205ceceb..194b2b403f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt @@ -17,22 +17,27 @@ package im.vector.app.features.settings.devtools import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject class IncomingKeyRequestListFragment @Inject constructor( val viewModelFactory: KeyRequestListViewModel.Factory, private val epoxyController: IncomingKeyRequestPagedController -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: KeyRequestListViewModel by fragmentViewModel(KeyRequestListViewModel::class) @@ -45,11 +50,11 @@ class IncomingKeyRequestListFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericRecyclerView.configureWith(epoxyController, showDivider = true) + views.genericRecyclerView.configureWith(epoxyController, showDivider = true) } override fun onDestroyView() { super.onDestroyView() - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt index ff91d9bba3..e9070ed7d8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt @@ -18,8 +18,11 @@ package im.vector.app.features.settings.devtools import android.app.Activity import android.os.Bundle +import android.view.LayoutInflater import android.view.MenuItem import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter @@ -35,18 +38,22 @@ import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.selectTxtFileToWrite -import kotlinx.android.synthetic.main.fragment_devtool_keyrequests.* +import im.vector.app.databinding.FragmentDevtoolKeyrequestsBinding +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject class KeyRequestsFragment @Inject constructor( - val viewModelFactory: KeyRequestViewModel.Factory) : VectorBaseFragment() { + val viewModelFactory: KeyRequestViewModel.Factory) : VectorBaseFragment() { - override fun getLayoutResId(): Int = R.layout.fragment_devtool_keyrequests + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDevtoolKeyrequestsBinding { + return FragmentDevtoolKeyrequestsBinding.inflate(inflater, container, false) + } override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.key_share_request) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.key_share_request) } private var mPagerAdapter: KeyReqPagerAdapter? = null @@ -70,8 +77,8 @@ class KeyRequestsFragment @Inject constructor( override fun invalidate() = withState(viewModel) { when (it.exporting) { - is Loading -> exportWaitingView.isVisible = true - else -> exportWaitingView.isVisible = false + is Loading -> views.exportWaitingView.isVisible = true + else -> views.exportWaitingView.isVisible = false } } @@ -83,10 +90,10 @@ class KeyRequestsFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mPagerAdapter = KeyReqPagerAdapter(this) - devToolKeyRequestPager.adapter = mPagerAdapter - devToolKeyRequestPager.registerOnPageChangeCallback(pageAdapterListener) + views.devToolKeyRequestPager.adapter = mPagerAdapter + views.devToolKeyRequestPager.registerOnPageChangeCallback(pageAdapterListener) - TabLayoutMediator(devToolKeyRequestTabs, devToolKeyRequestPager) { tab, position -> + TabLayoutMediator(views.devToolKeyRequestTabs, views.devToolKeyRequestPager) { tab, position -> when (position) { 0 -> { tab.text = "Outgoing" @@ -113,7 +120,7 @@ class KeyRequestsFragment @Inject constructor( } override fun onDestroyView() { - devToolKeyRequestPager.unregisterOnPageChangeCallback(pageAdapterListener) + views.devToolKeyRequestPager.unregisterOnPageChangeCallback(pageAdapterListener) mPagerAdapter = null super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt index 20132d8047..b0eefe195d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt @@ -17,22 +17,28 @@ package im.vector.app.features.settings.devtools import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject class OutgoingKeyRequestListFragment @Inject constructor( val viewModelFactory: KeyRequestListViewModel.Factory, private val epoxyController: OutgoingKeyRequestPagedController -) : VectorBaseFragment() { +) : VectorBaseFragment() { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } - override fun getLayoutResId() = R.layout.fragment_generic_recycler private val viewModel: KeyRequestListViewModel by fragmentViewModel(KeyRequestListViewModel::class) override fun invalidate() = withState(viewModel) { state -> @@ -41,13 +47,13 @@ class OutgoingKeyRequestListFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericRecyclerView.configureWith(epoxyController, showDivider = true) + views.genericRecyclerView.configureWith(epoxyController, showDivider = true) // epoxyController.interactionListener = this } override fun onDestroyView() { super.onDestroyView() - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() // epoxyController.interactionListener = null } } diff --git a/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt b/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt index 8bca7243a6..e766854d8c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt @@ -17,8 +17,11 @@ package im.vector.app.features.settings.ignored import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import com.airbnb.mvrx.Async import com.airbnb.mvrx.Loading @@ -30,26 +33,29 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_generic_recycler.* -import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject class VectorSettingsIgnoredUsersFragment @Inject constructor( val ignoredUsersViewModelFactory: IgnoredUsersViewModel.Factory, private val ignoredUsersController: IgnoredUsersController -) : VectorBaseFragment(), IgnoredUsersController.Callback { +) : VectorBaseFragment(), + IgnoredUsersController.Callback { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: IgnoredUsersViewModel by fragmentViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - waitingStatusText.setText(R.string.please_wait) - waitingStatusText.isVisible = true + views.waitingView.waitingStatusText.setText(R.string.please_wait) + views.waitingView.waitingStatusText.isVisible = true ignoredUsersController.callback = this - genericRecyclerView.configureWith(ignoredUsersController) + views.genericRecyclerView.configureWith(ignoredUsersController) viewModel.observeViewEvents { when (it) { is IgnoredUsersViewEvents.Loading -> showLoading(it.message) @@ -60,14 +66,14 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor( override fun onDestroyView() { ignoredUsersController.callback = null - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() super.onDestroyView() } override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_ignored_users) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_ignored_users) } override fun onUserIdClicked(userId: String) { @@ -91,9 +97,9 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor( } private fun handleUnIgnoreRequestStatus(unIgnoreRequest: Async) { - when (unIgnoreRequest) { - is Loading -> waiting_view.isVisible = true - else -> waiting_view.isVisible = false + views.waitingView.root.isVisible = when (unIgnoreRequest) { + is Loading -> true + else -> false } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt index e156528d3d..68d940cdd8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt @@ -17,7 +17,10 @@ package im.vector.app.features.settings.locale import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -27,22 +30,28 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.restart import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_locale_picker.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentLocalePickerBinding + import java.util.Locale import javax.inject.Inject class LocalePickerFragment @Inject constructor( private val viewModelFactory: LocalePickerViewModel.Factory, private val controller: LocalePickerController -) : VectorBaseFragment(), LocalePickerViewModel.Factory by viewModelFactory, LocalePickerController.Listener { +) : VectorBaseFragment(), + LocalePickerViewModel.Factory by viewModelFactory, + LocalePickerController.Listener { private val viewModel: LocalePickerViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_locale_picker + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocalePickerBinding { + return FragmentLocalePickerBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - localeRecyclerView.configureWith(controller) + views.localeRecyclerView.configureWith(controller) controller.listener = this viewModel.observeViewEvents { @@ -56,7 +65,7 @@ class LocalePickerFragment @Inject constructor( override fun onDestroyView() { super.onDestroyView() - localeRecyclerView.cleanup() + views.localeRecyclerView.cleanup() controller.listener = null } @@ -75,6 +84,6 @@ class LocalePickerFragment @Inject constructor( override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_select_language) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_select_language) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt index 0075d8ef5a..f2823c8074 100644 --- a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt @@ -17,8 +17,11 @@ package im.vector.app.features.settings.push import android.os.Bundle +import android.view.LayoutInflater import android.view.MenuItem import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -26,16 +29,19 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject // Referenced in vector_settings_notifications.xml class PushGatewaysFragment @Inject constructor( val pushGatewaysViewModelFactory: PushGatewaysViewModel.Factory, private val epoxyController: PushGateWayController -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: PushGatewaysViewModel by fragmentViewModel(PushGatewaysViewModel::class) @@ -54,16 +60,16 @@ class PushGatewaysFragment @Inject constructor( override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_notifications_targets) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_notifications_targets) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericRecyclerView.configureWith(epoxyController, showDivider = true) + views.genericRecyclerView.configureWith(epoxyController, showDivider = true) } override fun onDestroyView() { - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt index c5ad04380b..340f26a892 100644 --- a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt @@ -16,7 +16,10 @@ package im.vector.app.features.settings.push import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -24,30 +27,33 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import javax.inject.Inject // Referenced in vector_settings_notifications.xml class PushRulesFragment @Inject constructor( private val epoxyController: PushRulesController -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class) override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_push_rules) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_push_rules) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericRecyclerView.configureWith(epoxyController, showDivider = true) + views.genericRecyclerView.configureWith(epoxyController, showDivider = true) } override fun onDestroyView() { - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt index 12ff51dcbd..dd615eddf6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt @@ -18,8 +18,11 @@ package im.vector.app.features.settings.threepids import android.content.DialogInterface import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -35,7 +38,8 @@ import im.vector.app.core.extensions.isMsisdn import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding + import org.matrix.android.sdk.api.session.identity.ThreePid import javax.inject.Inject @@ -43,18 +47,20 @@ class ThreePidsSettingsFragment @Inject constructor( private val viewModelFactory: ThreePidsSettingsViewModel.Factory, private val epoxyController: ThreePidsSettingsController ) : - VectorBaseFragment(), + VectorBaseFragment(), OnBackPressed, ThreePidsSettingsViewModel.Factory by viewModelFactory, ThreePidsSettingsController.InteractionListener { private val viewModel: ThreePidsSettingsViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - genericRecyclerView.configureWith(epoxyController) + views.genericRecyclerView.configureWith(epoxyController) epoxyController.interactionListener = this viewModel.observeViewEvents { @@ -73,13 +79,13 @@ class ThreePidsSettingsFragment @Inject constructor( override fun onDestroyView() { super.onDestroyView() - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() epoxyController.interactionListener = null } override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_emails_and_phone_numbers_title) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_emails_and_phone_numbers_title) } override fun invalidate() = withState(viewModel) { state -> diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt index 321a2b3e94..65f1a05f29 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/NotificationTroubleshootRecyclerViewAdapter.kt @@ -22,7 +22,7 @@ import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import im.vector.app.R import im.vector.app.features.themes.ThemeUtils -import kotlinx.android.synthetic.main.item_notification_troubleshoot.view.* + class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList) : RecyclerView.Adapter() { diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt index 3977dfb990..5bac7744c5 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt @@ -21,10 +21,11 @@ import im.vector.app.R import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding -class IncomingShareActivity : VectorBaseActivity(), ToolbarConfigurable { +class IncomingShareActivity : VectorBaseActivity(), ToolbarConfigurable { - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun initUiAndData() { if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt index 92e383f8d1..7d0bee2efc 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt @@ -20,7 +20,9 @@ import android.app.Activity import android.content.ClipDescription import android.content.Intent import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.Toast import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog @@ -35,11 +37,13 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentIncomingShareBinding import im.vector.app.features.attachments.AttachmentsHelper import im.vector.app.features.attachments.preview.AttachmentsPreviewActivity import im.vector.app.features.attachments.preview.AttachmentsPreviewArgs import im.vector.app.features.login.LoginActivity -import kotlinx.android.synthetic.main.fragment_incoming_share.* + import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.room.model.RoomSummary import javax.inject.Inject @@ -52,12 +56,17 @@ class IncomingShareFragment @Inject constructor( val incomingShareViewModelFactory: IncomingShareViewModel.Factory, private val incomingShareController: IncomingShareController, private val sessionHolder: ActiveSessionHolder -) : VectorBaseFragment(), AttachmentsHelper.Callback, IncomingShareController.Callback { +) : + VectorBaseFragment(), + AttachmentsHelper.Callback, + IncomingShareController.Callback { private lateinit var attachmentsHelper: AttachmentsHelper private val viewModel: IncomingShareViewModel by fragmentViewModel() - override fun getLayoutResId() = R.layout.fragment_incoming_share + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentIncomingShareBinding { + return FragmentIncomingShareBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // If we are not logged in, stop the sharing process and open login screen. @@ -68,7 +77,7 @@ class IncomingShareFragment @Inject constructor( } super.onViewCreated(view, savedInstanceState) setupRecyclerView() - setupToolbar(incomingShareToolbar) + setupToolbar(views.incomingShareToolbar) attachmentsHelper = AttachmentsHelper(requireContext(), this).register() viewModel.observeViewEvents { @@ -103,7 +112,7 @@ class IncomingShareFragment @Inject constructor( cannotManageShare(R.string.error_handling_incoming_share) } - incomingShareSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + views.incomingShareSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { return true } @@ -113,7 +122,7 @@ class IncomingShareFragment @Inject constructor( return true } }) - sendShareButton.setOnClickListener { _ -> + views.sendShareButton.setOnClickListener { _ -> handleSendShare() } } @@ -154,12 +163,12 @@ class IncomingShareFragment @Inject constructor( override fun onDestroyView() { incomingShareController.callback = null - incomingShareRoomList.cleanup() + views.incomingShareRoomList.cleanup() super.onDestroyView() } private fun setupRecyclerView() { - incomingShareRoomList.configureWith(incomingShareController, hasFixedSize = true) + views.incomingShareRoomList.configureWith(incomingShareController, hasFixedSize = true) incomingShareController.callback = this } @@ -210,7 +219,7 @@ class IncomingShareFragment @Inject constructor( } override fun invalidate() = withState(viewModel) { - sendShareButton.isVisible = it.isInMultiSelectionMode + views.sendShareButton.isVisible = it.isInMultiSelectionMode incomingShareController.setData(it) } diff --git a/vector/src/main/java/im/vector/app/features/share/SharedData.kt b/vector/src/main/java/im/vector/app/features/share/SharedData.kt index 02d00ae401..ca0162658f 100644 --- a/vector/src/main/java/im/vector/app/features/share/SharedData.kt +++ b/vector/src/main/java/im/vector/app/features/share/SharedData.kt @@ -17,7 +17,7 @@ package im.vector.app.features.share import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.content.ContentAttachmentData sealed class SharedData : Parcelable { diff --git a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt index c04fe8153b..9f013cda30 100644 --- a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt +++ b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt @@ -21,18 +21,20 @@ import android.content.Intent import android.os.Bundle import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySignedOutBinding +import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs -import kotlinx.android.synthetic.main.activity_signed_out.* + import org.matrix.android.sdk.api.failure.GlobalError import timber.log.Timber /** * In this screen, the user is viewing a message informing that he has been logged out */ -class SignedOutActivity : VectorBaseActivity() { +class SignedOutActivity : VectorBaseActivity() { - override fun getLayoutRes() = R.layout.activity_signed_out + override fun getBinding() = ActivitySignedOutBinding.inflate(layoutInflater) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -41,7 +43,7 @@ class SignedOutActivity : VectorBaseActivity() { } private fun setupViews() { - signedOutSubmit.setOnClickListener { submit() } + views.signedOutSubmit.setOnClickListener { submit() } } private fun submit() { diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt index 5fb7a3e315..bbb6359aa1 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt @@ -30,7 +30,7 @@ import im.vector.app.core.extensions.replaceFragment import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs import im.vector.app.features.login.LoginActivity -import kotlinx.android.synthetic.main.activity_login.* + import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.session.Session import timber.log.Timber diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt index b85c9a8763..b40a02d3dd 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt @@ -18,7 +18,9 @@ package im.vector.app.features.signout.soft import android.content.DialogInterface import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState @@ -27,11 +29,12 @@ import im.vector.app.core.dialogs.withColoredButton import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.hideKeyboard +import im.vector.app.databinding.FragmentGenericRecyclerBinding import im.vector.app.features.login.AbstractLoginFragment import im.vector.app.features.login.LoginAction import im.vector.app.features.login.LoginMode import im.vector.app.features.login.LoginViewEvents -import kotlinx.android.synthetic.main.fragment_generic_recycler.* + import javax.inject.Inject /** @@ -41,11 +44,14 @@ import javax.inject.Inject */ class SoftLogoutFragment @Inject constructor( private val softLogoutController: SoftLogoutController -) : AbstractLoginFragment(), SoftLogoutController.Listener { +) : AbstractLoginFragment(), + SoftLogoutController.Listener { private val softLogoutViewModel: SoftLogoutViewModel by activityViewModel() - override fun getLayoutResId() = R.layout.fragment_generic_recycler + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -83,12 +89,12 @@ class SoftLogoutFragment @Inject constructor( } private fun setupRecyclerView() { - genericRecyclerView.configureWith(softLogoutController) + views.genericRecyclerView.configureWith(softLogoutController) softLogoutController.listener = this } override fun onDestroyView() { - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() softLogoutController.listener = null super.onDestroyView() } @@ -134,7 +140,7 @@ class SoftLogoutFragment @Inject constructor( } private fun cleanupUi() { - genericRecyclerView.hideKeyboard() + views.genericRecyclerView.hideKeyboard() } override fun forgetPasswordClicked() { diff --git a/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt b/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt index e5e28dcabb..c6bcb0a4e2 100755 --- a/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt +++ b/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt @@ -23,7 +23,7 @@ import android.widget.FrameLayout import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.utils.isAirplaneModeOn -import kotlinx.android.synthetic.main.view_sync_state.view.* + import org.matrix.android.sdk.api.session.sync.SyncState class SyncStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) diff --git a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsFragment.kt b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsFragment.kt index 10fcb65e12..97fa4710e0 100644 --- a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsFragment.kt @@ -16,7 +16,9 @@ package im.vector.app.features.terms import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.isVisible import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success @@ -30,17 +32,22 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.openUrlInChromeCustomTab -import kotlinx.android.synthetic.main.fragment_review_terms.* +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentReviewTermsBinding + import org.matrix.android.sdk.api.session.terms.TermsService import javax.inject.Inject class ReviewTermsFragment @Inject constructor( private val termsController: TermsController -) : VectorBaseFragment(), TermsController.Listener { +) : VectorBaseFragment(), + TermsController.Listener { private val reviewTermsViewModel: ReviewTermsViewModel by activityViewModel() - override fun getLayoutResId() = R.layout.fragment_review_terms + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentReviewTermsBinding { + return FragmentReviewTermsBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -79,7 +86,7 @@ class ReviewTermsFragment @Inject constructor( override fun onResume() { super.onResume() - (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.terms_of_service) + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.terms_of_service) } override fun invalidate() = withState(reviewTermsViewModel) { state -> diff --git a/vector/src/main/java/im/vector/app/features/terms/ServiceTermsArgs.kt b/vector/src/main/java/im/vector/app/features/terms/ServiceTermsArgs.kt index 50c9568204..af3f5aba11 100644 --- a/vector/src/main/java/im/vector/app/features/terms/ServiceTermsArgs.kt +++ b/vector/src/main/java/im/vector/app/features/terms/ServiceTermsArgs.kt @@ -16,7 +16,7 @@ package im.vector.app.features.terms import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.terms.TermsService @Parcelize diff --git a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt index 782d7e1c04..4a060c0fcc 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt @@ -20,7 +20,9 @@ import android.Manifest import android.app.Activity import android.content.pm.PackageManager import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.Toast import androidx.core.content.ContextCompat import com.airbnb.mvrx.activityViewModel @@ -32,18 +34,22 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.registerForPermissionsResult +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentQrCodeScannerWithButtonBinding import im.vector.lib.multipicker.MultiPicker import im.vector.lib.multipicker.utils.ImageUtils -import kotlinx.android.synthetic.main.fragment_qr_code_scanner_with_button.* + import me.dm7.barcodescanner.zxing.ZXingScannerView import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject class ScanUserCodeFragment @Inject constructor() - : VectorBaseFragment(), + : VectorBaseFragment(), ZXingScannerView.ResultHandler { - override fun getLayoutResId() = R.layout.fragment_qr_code_scanner_with_button + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeScannerWithButtonBinding { + return FragmentQrCodeScannerWithButtonBinding.inflate(inflater, container, false) + } val sharedViewModel: UserCodeSharedViewModel by activityViewModel() diff --git a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt index db6d636b9a..3aadd6c9bf 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt @@ -17,7 +17,9 @@ package im.vector.app.features.usercode import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -27,15 +29,19 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.startSharePlainTextIntent +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentUserCodeShowBinding import im.vector.app.features.home.AvatarRenderer -import kotlinx.android.synthetic.main.fragment_user_code_show.* + import javax.inject.Inject class ShowUserCodeFragment @Inject constructor( private val avatarRenderer: AvatarRenderer -) : VectorBaseFragment() { +) : VectorBaseFragment() { - override fun getLayoutResId() = R.layout.fragment_user_code_show + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentUserCodeShowBinding { + return FragmentUserCodeShowBinding.inflate(inflater, container, false) + } val sharedViewModel: UserCodeSharedViewModel by activityViewModel() @@ -49,15 +55,15 @@ class ShowUserCodeFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - showUserCodeClose.debouncedClicks { + views.showUserCodeClose.debouncedClicks { sharedViewModel.handle(UserCodeActions.DismissAction) } - showUserCodeScanButton.debouncedClicks { + views.showUserCodeScanButton.debouncedClicks { if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) { doOpenQRCodeScanner() } } - showUserCodeShareButton.debouncedClicks { + views.showUserCodeShareButton.debouncedClicks { sharedViewModel.handle(UserCodeActions.ShareByText) } @@ -79,9 +85,9 @@ class ShowUserCodeFragment @Inject constructor( } override fun invalidate() = withState(sharedViewModel) { state -> - state.matrixItem?.let { avatarRenderer.render(it, showUserCodeAvatar) } - state.shareLink?.let { showUserCodeQRImage.setData(it) } - showUserCodeCardNameText.setTextOrHide(state.matrixItem?.displayName) - showUserCodeCardUserIdText.setTextOrHide(state.matrixItem?.id) + state.matrixItem?.let { avatarRenderer.render(it, views.showUserCodeAvatar) } + state.shareLink?.let { views.showUserCodeQRImage.setData(it) } + views.showUserCodeCardNameText.setTextOrHide(state.matrixItem?.displayName) + views.showUserCodeCardUserIdText.setTextOrHide(state.matrixItem?.id) } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index 547e2d939f..0706fd296b 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -33,14 +33,16 @@ import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.onPermissionDeniedSnackbar +import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.features.matrixto.MatrixToBottomSheet -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.activity_simple.* +import kotlinx.parcelize.Parcelize + import javax.inject.Inject import kotlin.reflect.KClass -class UserCodeActivity - : VectorBaseActivity(), UserCodeSharedViewModel.Factory, MatrixToBottomSheet.InteractionListener { +class UserCodeActivity : VectorBaseActivity(), + UserCodeSharedViewModel.Factory, + MatrixToBottomSheet.InteractionListener { @Inject lateinit var viewModelFactory: UserCodeSharedViewModel.Factory @@ -51,7 +53,7 @@ class UserCodeActivity val userId: String ) : Parcelable - override fun getLayoutRes() = R.layout.activity_simple + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun injectWith(injector: ScreenComponent) { injector.inject(this) @@ -79,8 +81,8 @@ class UserCodeActivity sharedViewModel.observeViewEvents { when (it) { UserCodeShareViewEvents.Dismiss -> ActivityCompat.finishAfterTransition(this) - UserCodeShareViewEvents.ShowWaitingScreen -> simpleActivityWaitingView.isVisible = true - UserCodeShareViewEvents.HideWaitingScreen -> simpleActivityWaitingView.isVisible = false + UserCodeShareViewEvents.ShowWaitingScreen -> views.simpleActivityWaitingView.isVisible = true + UserCodeShareViewEvents.HideWaitingScreen -> views.simpleActivityWaitingView.isVisible = false is UserCodeShareViewEvents.ToastMessage -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() is UserCodeShareViewEvents.NavigateToRoom -> navigator.openRoom(this, it.roomId) UserCodeShareViewEvents.CameraPermissionNotGranted -> onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code) diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt index 4568878446..5611e79b40 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt @@ -17,9 +17,11 @@ package im.vector.app.features.userdirectory import android.os.Bundle +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.ViewGroup import android.widget.ScrollView import androidx.core.view.forEach import androidx.core.view.isVisible @@ -37,8 +39,10 @@ import im.vector.app.core.extensions.setupAsSearch import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.startSharePlainTextIntent +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentUserListBinding import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel -import kotlinx.android.synthetic.main.fragment_user_list.* + import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.user.model.User import javax.inject.Inject @@ -47,29 +51,32 @@ class UserListFragment @Inject constructor( private val userListController: UserListController, private val dimensionConverter: DimensionConverter, val homeServerCapabilitiesViewModelFactory: HomeServerCapabilitiesViewModel.Factory -) : VectorBaseFragment(), UserListController.Callback { +) : VectorBaseFragment(), + UserListController.Callback { private val args: UserListFragmentArgs by args() private val viewModel: UserListViewModel by activityViewModel() private val homeServerCapabilitiesViewModel: HomeServerCapabilitiesViewModel by fragmentViewModel() private lateinit var sharedActionViewModel: UserListSharedActionViewModel - override fun getLayoutResId() = R.layout.fragment_user_list + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentUserListBinding { + return FragmentUserListBinding.inflate(inflater, container, false) + } override fun getMenuRes() = args.menuResId override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(UserListSharedActionViewModel::class.java) - userListTitle.text = args.title - vectorBaseActivity.setSupportActionBar(userListToolbar) + views.userListTitle.text = args.title + vectorBaseActivity.setSupportActionBar(views.userListToolbar) setupRecyclerView() setupSearchView() setupCloseView() homeServerCapabilitiesViewModel.subscribe { - userListE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault + views.userListE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault } viewModel.selectSubscribe(this, UserListViewState::pendingInvitees) { @@ -93,7 +100,7 @@ class UserListFragment @Inject constructor( } override fun onDestroyView() { - userListRecyclerView.cleanup() + views.userListRecyclerView.cleanup() super.onDestroyView() } @@ -115,16 +122,16 @@ class UserListFragment @Inject constructor( private fun setupRecyclerView() { userListController.callback = this // Don't activate animation as we might have way to much item animation when filtering - userListRecyclerView.configureWith(userListController, disableItemAnimation = true) + views.userListRecyclerView.configureWith(userListController, disableItemAnimation = true) } private fun setupSearchView() { withState(viewModel) { - userListSearch.hint = getString(R.string.user_directory_search_hint) + views.userListSearch.hint = getString(R.string.user_directory_search_hint) } - userListSearch + views.userListSearch .textChanges() - .startWith(userListSearch.text) + .startWith(views.userListSearch.text) .subscribe { text -> val searchValue = text.trim() val action = if (searchValue.isBlank()) { @@ -136,12 +143,12 @@ class UserListFragment @Inject constructor( } .disposeOnDestroyView() - userListSearch.setupAsSearch() - userListSearch.requestFocus() + views.userListSearch.setupAsSearch() + views.userListSearch.requestFocus() } private fun setupCloseView() { - userListClose.debouncedClicks { + views.userListClose.debouncedClicks { requireActivity().finish() } } @@ -153,16 +160,16 @@ class UserListFragment @Inject constructor( private fun renderSelectedUsers(invitees: Set) { invalidateOptionsMenu() - val currentNumberOfChips = chipGroup.childCount + val currentNumberOfChips = views.chipGroup.childCount val newNumberOfChips = invitees.size - chipGroup.removeAllViews() + views.chipGroup.removeAllViews() invitees.forEach { addChipToGroup(it) } // Scroll to the bottom when adding chips. When removing chips, do not scroll if (newNumberOfChips >= currentNumberOfChips) { - chipGroupScrollView.post { - chipGroupScrollView.fullScroll(ScrollView.FOCUS_DOWN) + views.chipGroupScrollView.post { + views.chipGroupScrollView.fullScroll(ScrollView.FOCUS_DOWN) } } } @@ -175,7 +182,7 @@ class UserListFragment @Inject constructor( chip.isClickable = true chip.isCheckable = false chip.isCloseIconVisible = true - chipGroup.addView(chip) + views.chipGroup.addView(chip) chip.setOnCloseIconClickListener { viewModel.handle(UserListAction.RemovePendingInvitee(pendingInvitee)) } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt index 041f29a77a..02fd13b39b 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt @@ -17,7 +17,7 @@ package im.vector.app.features.userdirectory import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize @Parcelize data class UserListFragmentArgs( diff --git a/vector/src/main/java/im/vector/app/features/webview/ConsentWebViewEventListener.kt b/vector/src/main/java/im/vector/app/features/webview/ConsentWebViewEventListener.kt index 17e6fa4202..bd1935b972 100644 --- a/vector/src/main/java/im/vector/app/features/webview/ConsentWebViewEventListener.kt +++ b/vector/src/main/java/im/vector/app/features/webview/ConsentWebViewEventListener.kt @@ -29,12 +29,12 @@ private const val RIOT_BOT_ID = "@riot-bot:matrix.org" * This class is the Consent implementation of WebViewEventListener. * It is used to manage the consent agreement flow. */ -class ConsentWebViewEventListener(activity: VectorBaseActivity, +class ConsentWebViewEventListener(activity: VectorBaseActivity<*>, private val session: Session, private val delegate: WebViewEventListener) : WebViewEventListener by delegate { - private val safeActivity: VectorBaseActivity? by weak(activity) + private val safeActivity: VectorBaseActivity<*>? by weak(activity) override fun onPageFinished(url: String) { delegate.onPageFinished(url) diff --git a/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt b/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt index 5b761d1b3a..3aa848f551 100644 --- a/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt @@ -24,7 +24,9 @@ import androidx.annotation.CallSuper import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.platform.VectorBaseActivity -import kotlinx.android.synthetic.main.activity_vector_web_view.* +import im.vector.app.databinding.ActivitySimpleBinding +import im.vector.app.databinding.ActivityVectorWebViewBinding + import org.matrix.android.sdk.api.session.Session import javax.inject.Inject @@ -34,9 +36,9 @@ import javax.inject.Inject * It relies on the VectorWebViewClient * This class shouldn't be extended. To add new behaviors, you might create a new WebViewMode and a new WebViewEventListener */ -class VectorWebViewActivity : VectorBaseActivity() { +class VectorWebViewActivity : VectorBaseActivity() { - override fun getLayoutRes() = R.layout.activity_vector_web_view + override fun getBinding() = ActivityVectorWebViewBinding.inflate(layoutInflater) @Inject lateinit var session: Session @@ -46,10 +48,10 @@ class VectorWebViewActivity : VectorBaseActivity() { } override fun initUiAndData() { - configureToolbar(webview_toolbar) + configureToolbar(views.webviewToolbar) waitingView = findViewById(R.id.simple_webview_loader) - simple_webview.settings.apply { + views.simpleWebview.settings.apply { // Enable Javascript javaScriptEnabled = true @@ -70,7 +72,7 @@ class VectorWebViewActivity : VectorBaseActivity() { } val cookieManager = android.webkit.CookieManager.getInstance() - cookieManager.setAcceptThirdPartyCookies(simple_webview, true) + cookieManager.setAcceptThirdPartyCookies(views.simpleWebview, true) val url = intent.extras?.getString(EXTRA_URL) val title = intent.extras?.getString(EXTRA_TITLE, USE_TITLE_FROM_WEB_PAGE) @@ -80,15 +82,15 @@ class VectorWebViewActivity : VectorBaseActivity() { val webViewMode = intent.extras?.getSerializable(EXTRA_MODE) as WebViewMode val eventListener = webViewMode.eventListener(this, session) - simple_webview.webViewClient = VectorWebViewClient(eventListener) - simple_webview.webChromeClient = object : WebChromeClient() { + views.simpleWebview.webViewClient = VectorWebViewClient(eventListener) + views.simpleWebview.webChromeClient = object : WebChromeClient() { override fun onReceivedTitle(view: WebView, title: String) { if (title == USE_TITLE_FROM_WEB_PAGE) { setTitle(title) } } } - simple_webview.loadUrl(url) + views.simpleWebview.loadUrl(url) } /* ========================================================================================== @@ -96,8 +98,8 @@ class VectorWebViewActivity : VectorBaseActivity() { * ========================================================================================== */ override fun onBackPressed() { - if (simple_webview.canGoBack()) { - simple_webview.goBack() + if (views.simpleWebview.canGoBack()) { + views.simpleWebview.goBack() } else { super.onBackPressed() } diff --git a/vector/src/main/java/im/vector/app/features/webview/WebViewEventListenerFactory.kt b/vector/src/main/java/im/vector/app/features/webview/WebViewEventListenerFactory.kt index 64e08852b3..5bcfbb8eec 100644 --- a/vector/src/main/java/im/vector/app/features/webview/WebViewEventListenerFactory.kt +++ b/vector/src/main/java/im/vector/app/features/webview/WebViewEventListenerFactory.kt @@ -24,5 +24,5 @@ interface WebViewEventListenerFactory { /** * @return an instance of WebViewEventListener */ - fun eventListener(activity: VectorBaseActivity, session: Session): WebViewEventListener + fun eventListener(activity: VectorBaseActivity<*>, session: Session): WebViewEventListener } diff --git a/vector/src/main/java/im/vector/app/features/webview/WebViewMode.kt b/vector/src/main/java/im/vector/app/features/webview/WebViewMode.kt index edf98f66d8..58c8270154 100644 --- a/vector/src/main/java/im/vector/app/features/webview/WebViewMode.kt +++ b/vector/src/main/java/im/vector/app/features/webview/WebViewMode.kt @@ -25,12 +25,12 @@ import org.matrix.android.sdk.api.session.Session enum class WebViewMode : WebViewEventListenerFactory { DEFAULT { - override fun eventListener(activity: VectorBaseActivity, session: Session): WebViewEventListener { + override fun eventListener(activity: VectorBaseActivity<*>, session: Session): WebViewEventListener { return DefaultWebViewEventListener() } }, CONSENT { - override fun eventListener(activity: VectorBaseActivity, session: Session): WebViewEventListener { + override fun eventListener(activity: VectorBaseActivity<*>, session: Session): WebViewEventListener { return ConsentWebViewEventListener(activity, session, DefaultWebViewEventListener()) } }; diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt index d28fc134a9..d7f5407a38 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt @@ -28,16 +28,21 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding +import im.vector.app.databinding.ActivityWidgetBinding import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewEvents import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewModel import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewState -import kotlinx.android.synthetic.main.activity_widget.* + import org.matrix.android.sdk.api.session.events.model.Content import java.io.Serializable import javax.inject.Inject -class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewModel.Factory, RoomWidgetPermissionViewModel.Factory { +class WidgetActivity : VectorBaseActivity(), + ToolbarConfigurable, + WidgetViewModel.Factory, + RoomWidgetPermissionViewModel.Factory { companion object { @@ -69,7 +74,7 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewMode private val viewModel: WidgetViewModel by viewModel() private val permissionViewModel: RoomWidgetPermissionViewModel by viewModel() - override fun getLayoutRes() = R.layout.activity_widget + override fun getBinding() = ActivityWidgetBinding.inflate(layoutInflater) override fun getMenuRes() = R.menu.menu_widget @@ -85,8 +90,8 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewMode finish() return } - configure(toolbar) - toolbar.isVisible = widgetArgs.kind.nameRes != 0 + configure(views.toolbar) + views.toolbar.isVisible = widgetArgs.kind.nameRes != 0 viewModel.observeViewEvents { when (it) { is WidgetViewEvents.Close -> handleClose(it) diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt index 35d7867db3..45e682b1ce 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt @@ -21,9 +21,11 @@ import android.content.Intent import android.content.pm.PackageManager import android.os.Bundle import android.os.Parcelable +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.view.isInvisible import androidx.core.view.isVisible @@ -40,11 +42,13 @@ import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.openUrlInExternalBrowser +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.databinding.FragmentRoomWidgetBinding import im.vector.app.features.webview.WebViewEventListener import im.vector.app.features.widgets.webview.clearAfterWidget import im.vector.app.features.widgets.webview.setupForWidget -import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.fragment_room_widget.* +import kotlinx.parcelize.Parcelize + import org.matrix.android.sdk.api.session.terms.TermsService import timber.log.Timber import java.net.URISyntaxException @@ -59,12 +63,17 @@ data class WidgetArgs( val urlParams: Map = emptyMap() ) : Parcelable -class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventListener, OnBackPressed { +class WidgetFragment @Inject constructor() : + VectorBaseFragment(), + WebViewEventListener, + OnBackPressed { private val fragmentArgs: WidgetArgs by args() private val viewModel: WidgetViewModel by activityViewModel() - override fun getLayoutResId() = R.layout.fragment_room_widget + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomWidgetBinding { + return FragmentRoomWidgetBinding.inflate(inflater, container, false) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt index e1840fe687..2eef26e775 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt @@ -20,7 +20,9 @@ import android.os.Bundle import android.text.Spannable import android.text.SpannableStringBuilder import android.text.style.BulletSpan +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState @@ -28,15 +30,20 @@ import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.withArgs import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetRoomWidgetPermissionBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.widgets.WidgetArgs -import kotlinx.android.synthetic.main.bottom_sheet_room_widget_permission.* + import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject -class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() { +class RoomWidgetPermissionBottomSheet : + VectorBaseBottomSheetDialogFragment() { - override fun getLayoutResId(): Int = R.layout.bottom_sheet_room_widget_permission + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetRoomWidgetPermissionBinding { + return BottomSheetRoomWidgetPermissionBinding.inflate(inflater, container, false) + } private val viewModel: RoomWidgetPermissionViewModel by activityViewModel() @@ -58,17 +65,17 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() { } private fun setupViews() { - widgetPermissionDecline.setOnClickListener { doDecline() } - widgetPermissionContinue.setOnClickListener { doAccept() } + views.widgetPermissionDecline.setOnClickListener { doDecline() } + views.widgetPermissionContinue.setOnClickListener { doAccept() } } override fun invalidate() = withState(viewModel) { state -> super.invalidate() val permissionData = state.permissionData() ?: return@withState - widgetPermissionOwnerId.text = permissionData.widget.senderInfo?.userId ?: "" - widgetPermissionOwnerDisplayName.text = permissionData.widget.senderInfo?.disambiguatedDisplayName + views.widgetPermissionOwnerId.text = permissionData.widget.senderInfo?.userId ?: "" + views.widgetPermissionOwnerDisplayName.text = permissionData.widget.senderInfo?.disambiguatedDisplayName permissionData.widget.senderInfo?.toMatrixItem()?.also { - avatarRenderer.render(it, widgetPermissionOwnerAvatar) + avatarRenderer.render(it, views.widgetPermissionOwnerAvatar) } val domain = permissionData.widgetDomain ?: "" @@ -85,7 +92,7 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() { infoBuilder.append(bulletPoint, BulletSpan(resources.getDimension(R.dimen.quote_gap).toInt()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) } infoBuilder.append("\n") - widgetPermissionSharedInfo.text = infoBuilder + views.widgetPermissionSharedInfo.text = infoBuilder } private fun doDecline() { diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt index 8b014eb6a2..0c646d5d5e 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetActionButton.kt @@ -25,7 +25,7 @@ import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.features.themes.ThemeUtils -import kotlinx.android.synthetic.main.item_signout_action.view.* + class SignOutBottomSheetActionButton @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt index 49c688c801..f7834bf1de 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt @@ -19,7 +19,9 @@ package im.vector.app.features.workers.signout import android.app.Activity import android.app.Dialog import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.FrameLayout import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible @@ -35,17 +37,21 @@ import im.vector.app.core.dialogs.ExportKeysDialog import im.vector.app.core.extensions.queryExportKeys import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetLogoutAndBackupBinding import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity import im.vector.app.features.crypto.recover.BootstrapBottomSheet import im.vector.app.features.crypto.recover.SetupMode -import kotlinx.android.synthetic.main.bottom_sheet_logout_and_backup.* + import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import timber.log.Timber import javax.inject.Inject // TODO this needs to be refactored to current standard and remove legacy -class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), SignoutCheckViewModel.Factory { +class SignOutBottomSheetDialogFragment : + VectorBaseBottomSheetDialogFragment(), + SignoutCheckViewModel.Factory { var onSignOut: Runnable? = null @@ -78,11 +84,11 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setupRecoveryButton.action = { + views.setupRecoveryButton.action = { BootstrapBottomSheet.show(parentFragmentManager, SetupMode.NORMAL) } - exitAnywayButton.action = { + views.exitAnywayButton.action = { context?.let { AlertDialog.Builder(it) .setTitle(R.string.are_you_sure) @@ -95,17 +101,17 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), } } - signOutButton.action = { + views.signOutButton.action = { onSignOut?.run() } - exportManuallyButton.action = { + views.exportManuallyButton.action = { withState(viewModel) { state -> queryExportKeys(state.userId, manualExportKeysActivityResultLauncher) } } - setupMegolmBackupButton.action = { + views.setupMegolmBackupButton.action = { setupBackupActivityResultLauncher.launch(KeysBackupSetupActivity.intent(requireContext(), true)) } @@ -136,80 +142,80 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), } override fun invalidate() = withState(viewModel) { state -> - signoutExportingLoading.isVisible = false + views.signoutExportingLoading.isVisible = false if (state.crossSigningSetupAllKeysKnown && !state.backupIsSetup) { - bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) - backingUpStatusGroup.isVisible = false + views.bottomSheetSignoutWarningText.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) + views.backingUpStatusGroup.isVisible = false // we should show option to setup 4S - setupRecoveryButton.isVisible = true - setupMegolmBackupButton.isVisible = false + views.setupRecoveryButton.isVisible = true + views.setupMegolmBackupButton.isVisible = false // We let the option to ignore and quit - exportManuallyButton.isVisible = true - exitAnywayButton.isVisible = true - signOutButton.isVisible = false + views.exportManuallyButton.isVisible = true + views.exitAnywayButton.isVisible = true + views.signOutButton.isVisible = false } else if (state.keysBackupState == KeysBackupState.Unknown || state.keysBackupState == KeysBackupState.Disabled) { - bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) - backingUpStatusGroup.isVisible = false + views.bottomSheetSignoutWarningText.text = getString(R.string.sign_out_bottom_sheet_warning_no_backup) + views.backingUpStatusGroup.isVisible = false // no key backup and cannot setup full 4S // we propose to setup // we should show option to setup 4S - setupRecoveryButton.isVisible = false - setupMegolmBackupButton.isVisible = true + views.setupRecoveryButton.isVisible = false + views.setupMegolmBackupButton.isVisible = true // We let the option to ignore and quit - exportManuallyButton.isVisible = true - exitAnywayButton.isVisible = true - signOutButton.isVisible = false + views.exportManuallyButton.isVisible = true + views.exitAnywayButton.isVisible = true + views.signOutButton.isVisible = false } else { // so keybackup is setup // You should wait until all are uploaded - setupRecoveryButton.isVisible = false + views.setupRecoveryButton.isVisible = false when (state.keysBackupState) { KeysBackupState.ReadyToBackUp -> { - bottom_sheet_signout_warning_text.text = getString(R.string.action_sign_out_confirmation_simple) + views.bottomSheetSignoutWarningText.text = getString(R.string.action_sign_out_confirmation_simple) // Ok all keys are backedUp - backingUpStatusGroup.isVisible = true - backupProgress.isVisible = false - backupCompleteImage.isVisible = true - backupStatusText.text = getString(R.string.keys_backup_info_keys_all_backup_up) + views.backingUpStatusGroup.isVisible = true + views.backupProgress.isVisible = false + views.backupCompleteImage.isVisible = true + views.backupStatusText.text = getString(R.string.keys_backup_info_keys_all_backup_up) - setupMegolmBackupButton.isVisible = false - exportManuallyButton.isVisible = false - exitAnywayButton.isVisible = false + views.setupMegolmBackupButton.isVisible = false + views.exportManuallyButton.isVisible = false + views.exitAnywayButton.isVisible = false // You can signout - signOutButton.isVisible = true + views.signOutButton.isVisible = true } KeysBackupState.WillBackUp, KeysBackupState.BackingUp -> { - bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_backing_up) + views.bottomSheetSignoutWarningText.text = getString(R.string.sign_out_bottom_sheet_warning_backing_up) // save in progress - backingUpStatusGroup.isVisible = true - backupProgress.isVisible = true - backupCompleteImage.isVisible = false - backupStatusText.text = getString(R.string.sign_out_bottom_sheet_backing_up_keys) + views.backingUpStatusGroup.isVisible = true + views.backupProgress.isVisible = true + views.backupCompleteImage.isVisible = false + views.backupStatusText.text = getString(R.string.sign_out_bottom_sheet_backing_up_keys) - setupMegolmBackupButton.isVisible = false - exportManuallyButton.isVisible = false - exitAnywayButton.isVisible = true - signOutButton.isVisible = false + views.setupMegolmBackupButton.isVisible = false + views.exportManuallyButton.isVisible = false + views.exitAnywayButton.isVisible = true + views.signOutButton.isVisible = false } KeysBackupState.NotTrusted -> { - bottom_sheet_signout_warning_text.text = getString(R.string.sign_out_bottom_sheet_warning_backup_not_active) + views.bottomSheetSignoutWarningText.text = getString(R.string.sign_out_bottom_sheet_warning_backup_not_active) // It's not trusted and we know there are unsaved keys.. - backingUpStatusGroup.isVisible = false + views.backingUpStatusGroup.isVisible = false // option to enter pass/key - setupMegolmBackupButton.isVisible = true - exportManuallyButton.isVisible = true - exitAnywayButton.isVisible = true - signOutButton.isVisible = false + views.setupMegolmBackupButton.isVisible = true + views.exportManuallyButton.isVisible = true + views.exitAnywayButton.isVisible = true + views.signOutButton.isVisible = false } else -> { // mmm.. strange state - exitAnywayButton.isVisible = true + views.exitAnywayButton.isVisible = true } } } @@ -217,25 +223,25 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), // final call if keys have been exported when (state.hasBeenExportedToFile) { is Loading -> { - signoutExportingLoading.isVisible = true - backingUpStatusGroup.isVisible = false + views.signoutExportingLoading.isVisible = true + views.backingUpStatusGroup.isVisible = false - setupRecoveryButton.isVisible = false - setupMegolmBackupButton.isVisible = false - exportManuallyButton.isVisible = false - exitAnywayButton.isVisible = true - signOutButton.isVisible = false + views.setupRecoveryButton.isVisible = false + views.setupMegolmBackupButton.isVisible = false + views.exportManuallyButton.isVisible = false + views.exitAnywayButton.isVisible = true + views.signOutButton.isVisible = false } is Success -> { if (state.hasBeenExportedToFile.invoke()) { - bottom_sheet_signout_warning_text.text = getString(R.string.action_sign_out_confirmation_simple) - backingUpStatusGroup.isVisible = false + views.bottomSheetSignoutWarningText.text = getString(R.string.action_sign_out_confirmation_simple) + views.backingUpStatusGroup.isVisible = false - setupRecoveryButton.isVisible = false - setupMegolmBackupButton.isVisible = false - exportManuallyButton.isVisible = false - exitAnywayButton.isVisible = false - signOutButton.isVisible = true + views.setupRecoveryButton.isVisible = false + views.setupMegolmBackupButton.isVisible = false + views.exportManuallyButton.isVisible = false + views.exitAnywayButton.isVisible = false + views.signOutButton.isVisible = true } } else -> { @@ -244,7 +250,9 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), super.invalidate() } - override fun getLayoutResId() = R.layout.bottom_sheet_logout_and_backup + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetLogoutAndBackupBinding { + return BottomSheetLogoutAndBackupBinding.inflate(inflater, container, false) + } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) diff --git a/vector/src/main/res/layout/activity.xml b/vector/src/main/res/layout/activity.xml index e5f6655263..3e8adbbd35 100644 --- a/vector/src/main/res/layout/activity.xml +++ b/vector/src/main/res/layout/activity.xml @@ -26,7 +26,9 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbar" /> - + \ No newline at end of file diff --git a/vector/src/main/res/layout/activity_home.xml b/vector/src/main/res/layout/activity_home.xml index f8496f4116..50fc11500a 100644 --- a/vector/src/main/res/layout/activity_home.xml +++ b/vector/src/main/res/layout/activity_home.xml @@ -16,7 +16,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + diff --git a/vector/src/main/res/layout/activity_room_detail.xml b/vector/src/main/res/layout/activity_room_detail.xml index 4139aa12dc..aca4ee4e63 100644 --- a/vector/src/main/res/layout/activity_room_detail.xml +++ b/vector/src/main/res/layout/activity_room_detail.xml @@ -20,7 +20,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + diff --git a/vector/src/main/res/layout/fragment_create_room.xml b/vector/src/main/res/layout/fragment_create_room.xml index 3abcafc94d..b4f318ae76 100644 --- a/vector/src/main/res/layout/fragment_create_room.xml +++ b/vector/src/main/res/layout/fragment_create_room.xml @@ -67,7 +67,9 @@ - + diff --git a/vector/src/main/res/layout/fragment_generic_recycler.xml b/vector/src/main/res/layout/fragment_generic_recycler.xml index 4aded532e8..6ddbc5baab 100644 --- a/vector/src/main/res/layout/fragment_generic_recycler.xml +++ b/vector/src/main/res/layout/fragment_generic_recycler.xml @@ -13,6 +13,8 @@ app:itemSpacing="1dp" tools:listitem="@layout/item_pushgateway" /> - + diff --git a/vector/src/main/res/layout/fragment_matrix_profile.xml b/vector/src/main/res/layout/fragment_matrix_profile.xml index 288cbe82d4..c380ea293c 100644 --- a/vector/src/main/res/layout/fragment_matrix_profile.xml +++ b/vector/src/main/res/layout/fragment_matrix_profile.xml @@ -104,6 +104,8 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:listitem="@layout/item_profile_action" /> - + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_room_setting_generic.xml b/vector/src/main/res/layout/fragment_room_setting_generic.xml index 7ff63f3ce5..47650481e4 100644 --- a/vector/src/main/res/layout/fragment_room_setting_generic.xml +++ b/vector/src/main/res/layout/fragment_room_setting_generic.xml @@ -101,6 +101,8 @@ - + From dba65dcd2288acc764fe6ec108d241dc10cf4efc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 16 Dec 2020 02:05:38 +0100 Subject: [PATCH 005/224] Migrate to ViewBindings (#1072) - WIP --- tools/check/forbidden_strings_in_code.txt | 3 + .../debug/DebugMaterialThemeActivity.kt | 15 +- .../app/features/debug/TestLinkifyActivity.kt | 13 +- .../debug/sas/DebugSasEmojiActivity.kt | 6 +- .../core/dialogs/ConfirmationDialogBuilder.kt | 19 +- .../app/core/dialogs/ExportKeysDialog.kt | 34 ++- .../app/core/dialogs/ManuallyVerifyDialog.kt | 17 +- .../app/core/dialogs/PromptPasswordDialog.kt | 17 +- .../crypto/recover/KeepItSafeDialog.kt | 6 +- .../home/room/detail/RoomDetailFragment.kt | 205 +++++++++--------- .../room/detail/composer/TextComposerView.kt | 37 +++- .../RoomMemberProfileFragment.kt | 64 ++++-- .../powerlevel/EditPowerLevelDialogs.kt | 20 +- .../roomprofile/RoomProfileActivity.kt | 7 +- .../roomprofile/RoomProfileFragment.kt | 51 +++-- .../members/RoomMemberListFragment.kt | 26 +-- .../BackgroundSyncModeChooserDialog.kt | 8 +- .../settings/VectorSettingsGeneralFragment.kt | 70 +++--- ...ttingsNotificationsTroubleshootFragment.kt | 46 ++-- .../VectorSettingsSecurityPrivacyFragment.kt | 28 +-- .../deactivation/DeactivateAccountFragment.kt | 23 +- ...ficationTroubleshootRecyclerViewAdapter.kt | 65 +++--- .../app/features/terms/ReviewTermsFragment.kt | 15 +- .../features/usercode/ScanUserCodeFragment.kt | 18 +- .../app/features/widgets/WidgetFragment.kt | 56 ++--- .../signout/SignOutBottomSheetActionButton.kt | 10 +- .../res/layout/fragment_room_member_list.xml | 4 +- 27 files changed, 478 insertions(+), 405 deletions(-) diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index f19b9719a8..c65cc57adc 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -172,3 +172,6 @@ getSystemService\(Context ### Use DefaultSharedPreferences.getInstance() instead for better performance PreferenceManager\.getDefaultSharedPreferences==2 + +### Use ViewBindings +findViewById diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt index fb87ba6299..d290cc42fa 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt @@ -24,26 +24,27 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.snackbar.Snackbar import im.vector.app.R import im.vector.app.core.utils.toast - +import im.vector.app.databinding.ActivityTestMaterialThemeBinding // Rendering is not the same with VectorBaseActivity abstract class DebugMaterialThemeActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_test_material_theme) + val views = ActivityTestMaterialThemeBinding.inflate(layoutInflater) + setContentView(views.root) - debugShowSnackbar.setOnClickListener { - Snackbar.make(debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT) + views.debugShowSnackbar.setOnClickListener { + Snackbar.make(views.debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT) .setAction("Action") { } .show() } - debugShowToast.setOnClickListener { + views.debugShowToast.setOnClickListener { toast("Toast") } - debugShowDialog.setOnClickListener { + views.debugShowDialog.setOnClickListener { AlertDialog.Builder(this) .setMessage("Dialog content") .setIcon(R.drawable.ic_settings_x) @@ -53,7 +54,7 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() { .show() } - debugShowBottomSheet.setOnClickListener { + views.debugShowBottomSheet.setOnClickListener { BottomSheetDialogFragment().show(supportFragmentManager, "TAG") } } diff --git a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt index ce1deef104..b61c5bb195 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt @@ -22,15 +22,16 @@ import android.view.ViewGroup import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import im.vector.app.R - +import im.vector.app.databinding.ActivityTestLinkifyBinding +import im.vector.app.databinding.ActivityTestMaterialThemeBinding class TestLinkifyActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_test_linkify) - - test_linkify_content_view.removeAllViews() + val views = ActivityTestLinkifyBinding.inflate(layoutInflater) + setContentView(views.root) + views.testLinkifyContentView.removeAllViews() listOf( "https://www.html5rocks.com/en/tutorials/webrtc/basics/ |", @@ -79,7 +80,7 @@ class TestLinkifyActivity : AppCompatActivity() { ) .forEach { textContent -> val item = LayoutInflater.from(this) - .inflate(R.layout.item_test_linkify, test_linkify_content_view, false) + .inflate(R.layout.item_test_linkify, views.testLinkifyContentView, false) item.findViewById(R.id.test_linkify_auto_text) ?.apply { @@ -115,7 +116,7 @@ class TestLinkifyActivity : AppCompatActivity() { // TODO Call VectorLinkify.addLinks(text) } - test_linkify_content_view.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) + views.testLinkifyContentView.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) } } } diff --git a/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt index 7871fa0971..a502ebc75c 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt @@ -21,14 +21,18 @@ import androidx.appcompat.app.AppCompatActivity import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith +import im.vector.app.databinding.FragmentGenericRecyclerBinding import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis class DebugSasEmojiActivity : AppCompatActivity() { + private lateinit var views: FragmentGenericRecyclerBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.fragment_generic_recycler) + views = FragmentGenericRecyclerBinding.inflate(layoutInflater) + setContentView(views.root) val controller = SasEmojiController() views.genericRecyclerView.configureWith(controller) controller.setData(SasState(getAllVerificationEmojis())) diff --git a/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt b/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt index ca1e9a2a2d..ed429b30c6 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt @@ -21,7 +21,7 @@ import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import im.vector.app.R - +import im.vector.app.databinding.DialogConfirmationWithReasonBinding object ConfirmationDialogBuilder { @@ -33,25 +33,26 @@ object ConfirmationDialogBuilder { @StringRes reasonHintRes: Int, confirmation: (String?) -> Unit) { val layout = activity.layoutInflater.inflate(R.layout.dialog_confirmation_with_reason, null) - layout.dialogConfirmationText.setText(confirmationRes) + val views = DialogConfirmationWithReasonBinding.bind(layout) + views.dialogConfirmationText.setText(confirmationRes) - layout.dialogReasonCheck.isVisible = askForReason - layout.dialogReasonTextInputLayout.isVisible = askForReason + views.dialogReasonCheck.isVisible = askForReason + views.dialogReasonTextInputLayout.isVisible = askForReason - layout.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked -> - layout.dialogReasonTextInputLayout.isEnabled = isChecked + views.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked -> + views.dialogReasonTextInputLayout.isEnabled = isChecked } if (askForReason && reasonHintRes != 0) { - layout.dialogReasonInput.setHint(reasonHintRes) + views.dialogReasonInput.setHint(reasonHintRes) } AlertDialog.Builder(activity) .setTitle(titleRes) .setView(layout) .setPositiveButton(positiveRes) { _, _ -> - val reason = layout.dialogReasonInput.text.toString() + val reason = views.dialogReasonInput.text.toString() .takeIf { askForReason } - ?.takeIf { layout.dialogReasonCheck.isChecked } + ?.takeIf { views.dialogReasonCheck.isChecked } ?.takeIf { it.isNotBlank() } confirmation(reason) } diff --git a/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt b/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt index b4087d5ce1..a285e8458f 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt @@ -26,6 +26,7 @@ import com.google.android.material.textfield.TextInputLayout import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.SimpleTextWatcher +import im.vector.app.databinding.DialogExportE2eKeysBinding class ExportKeysDialog { @@ -33,48 +34,45 @@ class ExportKeysDialog { fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) { val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null) + val views = DialogExportE2eKeysBinding.bind(dialogLayout) val builder = AlertDialog.Builder(activity) .setTitle(R.string.encryption_export_room_keys) .setView(dialogLayout) - val passPhrase1EditText = dialogLayout.findViewById(R.id.exportDialogEt) - val passPhrase2EditText = dialogLayout.findViewById(R.id.exportDialogEtConfirm) - val passPhrase2Til = dialogLayout.findViewById(R.id.exportDialogTilConfirm) - val exportButton = dialogLayout.findViewById
  • -
  • - EventBus -
    - Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org) -
  • LazyThreeTenBp
    From 6e8d93bc6fd699290883de657232e04950c0b2b4 Mon Sep 17 00:00:00 2001 From: Yves Quemener Date: Wed, 6 Jan 2021 11:22:25 +0900 Subject: [PATCH 141/224] Fix in the test homeserver set-up instruction I think I removed a typo. You probably don't want a new virtualenv every time you start a homeserver? --- docs/ui-tests.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/ui-tests.md b/docs/ui-tests.md index ff01da0b31..6ebb52abe8 100644 --- a/docs/ui-tests.md +++ b/docs/ui-tests.md @@ -27,7 +27,6 @@ $ source env/bin/activate Every time you want to launch these test homeservers, type: ```shell script -$ virtualenv -p python3 env $ source env/bin/activate (env) $ demo/start.sh --no-rate-limit ``` From 22c10f5ada6d2014af0a7743d2b2bb49c3a6e9be Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Jan 2021 12:24:47 +0100 Subject: [PATCH 142/224] Prefer immutable type --- .../session/room/model/PowerLevelsContent.kt | 24 +++++++++++-------- .../home/room/detail/RoomDetailViewModel.kt | 10 ++++---- .../RoomMemberProfileViewModel.kt | 6 +++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt index 696b612389..c466486ec0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt @@ -30,23 +30,27 @@ data class PowerLevelsContent( @Json(name = "invite") val invite: Int = Role.Moderator.value, @Json(name = "redact") val redact: Int = Role.Moderator.value, @Json(name = "events_default") val eventsDefault: Int = Role.Default.value, - @Json(name = "events") val events: MutableMap = HashMap(), + @Json(name = "events") val events: Map = emptyMap(), @Json(name = "users_default") val usersDefault: Int = Role.Default.value, - @Json(name = "users") val users: MutableMap = HashMap(), + @Json(name = "users") val users: Map = emptyMap(), @Json(name = "state_default") val stateDefault: Int = Role.Moderator.value, - @Json(name = "notifications") val notifications: Map = HashMap() + @Json(name = "notifications") val notifications: Map = emptyMap() ) { /** - * Alter this content with a new power level for the specified user + * Return a copy of this content with a new power level for the specified user * * @param userId the userId to alter the power level of * @param powerLevel the new power level, or null to set the default value. */ - fun setUserPowerLevel(userId: String, powerLevel: Int?) { - if (powerLevel == null || powerLevel == usersDefault) { - users.remove(userId) - } else { - users[userId] = powerLevel - } + fun setUserPowerLevel(userId: String, powerLevel: Int?): PowerLevelsContent { + return copy( + users = users.toMutableMap().apply { + if (powerLevel == null || powerLevel == usersDefault) { + remove(userId) + } else { + put(userId, powerLevel) + } + } + ) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 1e6e7c9d14..975eda5d2f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -887,13 +887,15 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun handleSetUserPowerLevel(setUserPowerLevel: ParsedCommand.SetUserPowerLevel) { - val currentPowerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS) + val newPowerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS) ?.content - ?.toModel() ?: return + ?.toModel() + ?.setUserPowerLevel(setUserPowerLevel.userId, setUserPowerLevel.powerLevel) + ?.toContent() + ?: return launchSlashCommandFlowSuspendable { - currentPowerLevelsContent.setUserPowerLevel(setUserPowerLevel.userId, setUserPowerLevel.powerLevel) - room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent()) + room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent) } } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt index 39b5884308..8211a05127 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt @@ -162,11 +162,13 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v } else if (action.askForValidation && state.isMine) { _viewEvents.post(RoomMemberProfileViewEvents.ShowPowerLevelDemoteWarning(action.previousValue, action.newValue)) } else { - currentPowerLevelsContent.setUserPowerLevel(state.userId, action.newValue) + val newPowerLevelsContent = currentPowerLevelsContent + .setUserPowerLevel(state.userId, action.newValue) + .toContent() viewModelScope.launch { _viewEvents.post(RoomMemberProfileViewEvents.Loading()) try { - room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent()) + room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent) _viewEvents.post(RoomMemberProfileViewEvents.OnSetPowerLevelSuccess) } catch (failure: Throwable) { _viewEvents.post(RoomMemberProfileViewEvents.Failure(failure)) From c4a019f0d36344be339a6411c72b7a86a53d221d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Jan 2021 16:15:01 +0100 Subject: [PATCH 143/224] Edit room permissions (#2471) --- CHANGES.md | 1 + .../im/vector/app/core/di/FragmentModule.kt | 6 + .../RoomMemberProfileFragment.kt | 2 +- .../powerlevel/EditPowerLevelDialogs.kt | 8 +- .../roomprofile/RoomProfileActivity.kt | 19 ++- .../roomprofile/RoomProfileSharedAction.kt | 1 + .../permissions/EditablePermission.kt | 104 +++++++++++++ .../permissions/RoomPermissionsAction.kt | 23 +++ .../permissions/RoomPermissionsController.kt | 144 ++++++++++++++++++ .../permissions/RoomPermissionsFragment.kt | 102 +++++++++++++ .../permissions/RoomPermissionsViewEvents.kt | 28 ++++ .../permissions/RoomPermissionsViewModel.kt | 144 ++++++++++++++++++ .../permissions/RoomPermissionsViewState.kt | 40 +++++ .../settings/RoomSettingsController.kt | 11 ++ .../settings/RoomSettingsFragment.kt | 4 + vector/src/main/res/values/strings.xml | 26 ++++ 16 files changed, 654 insertions(+), 9 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/permissions/EditablePermission.kt create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewEvents.kt create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt diff --git a/CHANGES.md b/CHANGES.md index 7d4678fe40..ff457cb539 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ Changes in Element 1.0.14 (2020-XX-XX) Features ✨: - Enable url previews for notices (#2562) + - Edit room permissions (#2471) Improvements 🙌: - Add System theme option and set as default (#904) (#2387) diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index 87ab875746..407aa2fc73 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -84,6 +84,7 @@ import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment import im.vector.app.features.roomprofile.members.RoomMemberListFragment import im.vector.app.features.roomprofile.settings.RoomSettingsFragment import im.vector.app.features.roomprofile.alias.RoomAliasFragment +import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment @@ -364,6 +365,11 @@ interface FragmentModule { @FragmentKey(RoomAliasFragment::class) fun bindRoomAliasFragment(fragment: RoomAliasFragment): Fragment + @Binds + @IntoMap + @FragmentKey(RoomPermissionsFragment::class) + fun bindRoomPermissionsFragment(fragment: RoomPermissionsFragment): Fragment + @Binds @IntoMap @FragmentKey(RoomMemberProfileFragment::class) diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt index 08a251834e..688f74ba5d 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -324,7 +324,7 @@ class RoomMemberProfileFragment @Inject constructor( } override fun onEditPowerLevel(currentRole: Role) { - EditPowerLevelDialogs.showChoice(requireActivity(), currentRole) { newPowerLevel -> + EditPowerLevelDialogs.showChoice(requireActivity(), R.string.power_level_edit_title, currentRole) { newPowerLevel -> viewModel.handle(RoomMemberProfileAction.SetPowerLevel(currentRole.value, newPowerLevel, true)) } } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt index 4316a4bd0d..764271f7ce 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/powerlevel/EditPowerLevelDialogs.kt @@ -19,6 +19,7 @@ package im.vector.app.features.roommemberprofile.powerlevel import android.app.Activity import android.content.DialogInterface import android.view.KeyEvent +import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import im.vector.app.R @@ -29,7 +30,10 @@ import org.matrix.android.sdk.api.session.room.powerlevels.Role object EditPowerLevelDialogs { - fun showChoice(activity: Activity, currentRole: Role, listener: (Int) -> Unit) { + fun showChoice(activity: Activity, + @StringRes titleRes: Int, + currentRole: Role, + listener: (Int) -> Unit) { val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_edit_power_level, null) val views = DialogEditPowerLevelBinding.bind(dialogLayout) views.powerLevelRadioGroup.setOnCheckedChangeListener { _, checkedId -> @@ -45,7 +49,7 @@ object EditPowerLevelDialogs { } AlertDialog.Builder(activity) - .setTitle(R.string.power_level_edit_title) + .setTitle(titleRes) .setView(dialogLayout) .setPositiveButton(R.string.edit) { _, _ -> val newValue = when (views.powerLevelRadioGroup.checkedRadioButtonId) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt index 76649d53b3..7cb713d378 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt @@ -27,6 +27,7 @@ import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragmentToBackstack +import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivitySimpleBinding @@ -38,6 +39,7 @@ import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment import im.vector.app.features.roomprofile.members.RoomMemberListFragment import im.vector.app.features.roomprofile.settings.RoomSettingsFragment import im.vector.app.features.roomprofile.alias.RoomAliasFragment +import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment import javax.inject.Inject @@ -102,12 +104,13 @@ class RoomProfileActivity : .observe() .subscribe { sharedAction -> when (sharedAction) { - is RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers() - is RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings() - is RoomProfileSharedAction.OpenRoomAliasesSettings -> openRoomAlias() - is RoomProfileSharedAction.OpenRoomUploads -> openRoomUploads() - is RoomProfileSharedAction.OpenBannedRoomMembers -> openBannedRoomMembers() - } + RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers() + RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings() + RoomProfileSharedAction.OpenRoomAliasesSettings -> openRoomAlias() + RoomProfileSharedAction.OpenRoomPermissionsSettings -> openRoomPermissions() + RoomProfileSharedAction.OpenRoomUploads -> openRoomUploads() + RoomProfileSharedAction.OpenBannedRoomMembers -> openBannedRoomMembers() + }.exhaustive } .disposeOnDestroy() @@ -144,6 +147,10 @@ class RoomProfileActivity : addFragmentToBackstack(R.id.simpleFragmentContainer, RoomAliasFragment::class.java, roomProfileArgs) } + private fun openRoomPermissions() { + addFragmentToBackstack(R.id.simpleFragmentContainer, RoomPermissionsFragment::class.java, roomProfileArgs) + } + private fun openRoomMembers() { addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt index 83a610cf1b..2a5775d1af 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt @@ -24,6 +24,7 @@ import im.vector.app.core.platform.VectorSharedAction sealed class RoomProfileSharedAction : VectorSharedAction { object OpenRoomSettings : RoomProfileSharedAction() object OpenRoomAliasesSettings : RoomProfileSharedAction() + object OpenRoomPermissionsSettings : RoomProfileSharedAction() object OpenRoomUploads : RoomProfileSharedAction() object OpenRoomMembers : RoomProfileSharedAction() object OpenBannedRoomMembers : RoomProfileSharedAction() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/EditablePermission.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/EditablePermission.kt new file mode 100644 index 0000000000..bb1054b704 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/EditablePermission.kt @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021 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.app.features.roomprofile.permissions + +import androidx.annotation.StringRes +import im.vector.app.R +import org.matrix.android.sdk.api.session.events.model.EventType + +/** + * Change on each permission has an effect on the power level event. Try to sort the effect by category. + */ +sealed class EditablePermission(@StringRes val labelResId: Int) { + // Updates `content.events.[eventType]` + open class EventTypeEditablePermission(val eventType: String, @StringRes labelResId: Int) : EditablePermission(labelResId) + + class ModifyWidgets : EventTypeEditablePermission( + // Note: Element Web still use legacy value + EventType.STATE_ROOM_WIDGET_LEGACY, + R.string.room_permissions_modify_widgets + ) + + class ChangeRoomAvatar : EventTypeEditablePermission( + EventType.STATE_ROOM_AVATAR, + R.string.room_permissions_change_room_avatar + ) + + class ChangeMainAddressForTheRoom : EventTypeEditablePermission( + EventType.STATE_ROOM_CANONICAL_ALIAS, + R.string.room_permissions_change_main_address_for_the_room + ) + + class EnableRoomEncryption : EventTypeEditablePermission( + EventType.STATE_ROOM_ENCRYPTION, + R.string.room_permissions_enable_room_encryption + ) + + class ChangeHistoryVisibility : EventTypeEditablePermission( + EventType.STATE_ROOM_HISTORY_VISIBILITY, + R.string.room_permissions_change_history_visibility + ) + + class ChangeRoomName : EventTypeEditablePermission( + EventType.STATE_ROOM_NAME, + R.string.room_permissions_change_room_name + ) + + class ChangePermissions : EventTypeEditablePermission( + EventType.STATE_ROOM_POWER_LEVELS, + R.string.room_permissions_change_permissions + ) + + class SendRoomServerAclEvents : EventTypeEditablePermission( + EventType.STATE_ROOM_SERVER_ACL, + R.string.room_permissions_send_m_room_server_acl_events + ) + + class UpgradeTheRoom : EventTypeEditablePermission( + EventType.STATE_ROOM_TOMBSTONE, + R.string.room_permissions_upgrade_the_room + ) + + class ChangeTopic : EventTypeEditablePermission( + EventType.STATE_ROOM_TOPIC, + R.string.room_permissions_change_topic + ) + + // Updates `content.users_default` + class DefaultRole : EditablePermission(R.string.room_permissions_default_role) + + // Updates `content.events_default` + class SendMessages : EditablePermission(R.string.room_permissions_send_messages) + + // Updates `content.invites` + class InviteUsers : EditablePermission(R.string.room_permissions_invite_users) + + // Updates `content.state_default` + class ChangeSettings : EditablePermission(R.string.room_permissions_change_settings) + + // Updates `content.kick` + class KickUsers : EditablePermission(R.string.room_permissions_kick_users) + + // Updates `content.ban` + class BanUsers : EditablePermission(R.string.room_permissions_ban_users) + + // Updates `content.redact` + class RemoveMessagesSentByOthers : EditablePermission(R.string.room_permissions_remove_messages_sent_by_others) + + // Updates `content.notification.room` + class NotifyEveryone : EditablePermission(R.string.room_permissions_notify_everyone) +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt new file mode 100644 index 0000000000..32d9236fb6 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2021 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.app.features.roomprofile.permissions + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class RoomPermissionsAction : VectorViewModelAction { + data class UpdatePermission(val editablePermission: EditablePermission, val powerLevel: Int) : RoomPermissionsAction() +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt new file mode 100644 index 0000000000..058f5a9ce7 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2021 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.app.features.roomprofile.permissions + +import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.mvrx.Success +import im.vector.app.R +import im.vector.app.core.epoxy.loadingItem +import im.vector.app.core.epoxy.profiles.buildProfileAction +import im.vector.app.core.epoxy.profiles.buildProfileSection +import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.discovery.settingsInfoItem +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.powerlevels.Role +import javax.inject.Inject + +class RoomPermissionsController @Inject constructor( + private val stringProvider: StringProvider, + colorProvider: ColorProvider +) : TypedEpoxyController() { + + interface Callback { + fun onEditPermission(editablePermission: EditablePermission, currentRole: Role) + } + + var callback: Callback? = null + + private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color) + + // Order is the order applied in the UI + private val allEditablePermissions = listOf( + EditablePermission.DefaultRole(), + EditablePermission.SendMessages(), + EditablePermission.InviteUsers(), + EditablePermission.ChangeSettings(), + EditablePermission.KickUsers(), + EditablePermission.BanUsers(), + EditablePermission.RemoveMessagesSentByOthers(), + EditablePermission.NotifyEveryone(), + EditablePermission.ModifyWidgets(), + EditablePermission.ChangeRoomAvatar(), + EditablePermission.ChangeMainAddressForTheRoom(), + EditablePermission.EnableRoomEncryption(), + EditablePermission.ChangeHistoryVisibility(), + EditablePermission.ChangeRoomName(), + EditablePermission.ChangePermissions(), + EditablePermission.SendRoomServerAclEvents(), + EditablePermission.UpgradeTheRoom(), + EditablePermission.ChangeTopic() + ) + + init { + setData(null) + } + + override fun buildModels(data: RoomPermissionsViewState?) { + buildProfileSection( + stringProvider.getString(R.string.room_permissions_title) + ) + + settingsInfoItem { + id("notice") + helperText(stringProvider.getString(R.string.room_permissions_notice)) + } + + when (val content = data?.currentPowerLevelsContent) { + is Success -> buildPermissions(data, content()) + else -> { + loadingItem { + id("loading") + loadingText(stringProvider.getString(R.string.loading)) + } + } + } + } + + private fun buildPermissions(data: RoomPermissionsViewState, content: PowerLevelsContent) { + allEditablePermissions.forEach { editablePermission -> + val currentRole = getCurrentRole(editablePermission, content) + buildProfileAction( + id = editablePermission.labelResId.toString(), + title = stringProvider.getString(editablePermission.labelResId), + subtitle = getSubtitle(currentRole), + dividerColor = dividerColor, + divider = true, + editable = data.actionPermissions.canChangePowerLevels, + action = { callback?.onEditPermission(editablePermission, currentRole) } + ) + } + } + + private fun getSubtitle(currentRole: Role): String { + return when (currentRole) { + Role.Admin, + Role.Moderator, + Role.Default -> stringProvider.getString(currentRole.res) + is Role.Custom -> stringProvider.getString(currentRole.res, currentRole.value) + } + } + + private fun getCurrentRole(editablePermission: EditablePermission, content: PowerLevelsContent): Role { + val value = when (editablePermission) { + is EditablePermission.EventTypeEditablePermission -> content.events[editablePermission.eventType] ?: content.stateDefault + is EditablePermission.DefaultRole -> content.usersDefault + is EditablePermission.SendMessages -> content.eventsDefault + is EditablePermission.InviteUsers -> content.invite + is EditablePermission.ChangeSettings -> content.stateDefault + is EditablePermission.KickUsers -> content.kick + is EditablePermission.BanUsers -> content.ban + is EditablePermission.RemoveMessagesSentByOthers -> content.redact + is EditablePermission.NotifyEveryone -> (content.notifications["room"] as? Int) ?: Role.Moderator.value + } + + return Role.fromValue( + value, + when (editablePermission) { + is EditablePermission.EventTypeEditablePermission -> content.stateDefault + is EditablePermission.DefaultRole -> Role.Default.value + is EditablePermission.SendMessages -> Role.Default.value + is EditablePermission.InviteUsers -> Role.Moderator.value + is EditablePermission.ChangeSettings -> Role.Moderator.value + is EditablePermission.KickUsers -> Role.Moderator.value + is EditablePermission.BanUsers -> Role.Moderator.value + is EditablePermission.RemoveMessagesSentByOthers -> Role.Moderator.value + is EditablePermission.NotifyEveryone -> Role.Moderator.value + } + ) + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt new file mode 100644 index 0000000000..73e0b00de9 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2021 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.app.features.roomprofile.permissions + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import com.airbnb.mvrx.args +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +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.exhaustive +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.utils.toast +import im.vector.app.databinding.FragmentRoomSettingGenericBinding +import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs +import im.vector.app.features.roomprofile.RoomProfileArgs +import org.matrix.android.sdk.api.session.room.powerlevels.Role +import org.matrix.android.sdk.api.util.toMatrixItem +import javax.inject.Inject + +class RoomPermissionsFragment @Inject constructor( + val viewModelFactory: RoomPermissionsViewModel.Factory, + private val controller: RoomPermissionsController, + private val avatarRenderer: AvatarRenderer +) : + VectorBaseFragment(), + RoomPermissionsController.Callback { + + private val viewModel: RoomPermissionsViewModel by fragmentViewModel() + + private val roomProfileArgs: RoomProfileArgs by args() + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding { + return FragmentRoomSettingGenericBinding.inflate(inflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + controller.callback = this + setupToolbar(views.roomSettingsToolbar) + views.roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true) + views.waitingView.waitingStatusText.setText(R.string.please_wait) + views.waitingView.waitingStatusText.isVisible = true + + viewModel.observeViewEvents { + when (it) { + is RoomPermissionsViewEvents.Failure -> showFailure(it.throwable) + RoomPermissionsViewEvents.Success -> showSuccess() + }.exhaustive + } + } + + private fun showSuccess() { + activity?.toast(R.string.room_settings_save_success) + } + + override fun onDestroyView() { + controller.callback = null + views.roomSettingsRecyclerView.cleanup() + super.onDestroyView() + } + + override fun invalidate() = withState(viewModel) { state -> + views.waitingView.root.isVisible = state.isLoading + controller.setData(state) + renderRoomSummary(state) + } + + private fun renderRoomSummary(state: RoomPermissionsViewState) { + state.roomSummary()?.let { + views.roomSettingsToolbarTitleView.text = it.displayName + avatarRenderer.render(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView) + } + } + + override fun onEditPermission(editablePermission: EditablePermission, currentRole: Role) { + EditPowerLevelDialogs.showChoice(requireActivity(), editablePermission.labelResId, currentRole) { newPowerLevel -> + viewModel.handle(RoomPermissionsAction.UpdatePermission(editablePermission, newPowerLevel)) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewEvents.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewEvents.kt new file mode 100644 index 0000000000..8994398cf3 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewEvents.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2021 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.app.features.roomprofile.permissions + +import im.vector.app.core.platform.VectorViewEvents + +/** + * Transient events for room settings screen + */ +sealed class RoomPermissionsViewEvents : VectorViewEvents { + data class Failure(val throwable: Throwable) : RoomPermissionsViewEvents() + object Success : RoomPermissionsViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt new file mode 100644 index 0000000000..95217c1885 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2021 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.app.features.roomprofile.permissions + +import androidx.lifecycle.viewModelScope +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper +import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.rx.unwrap + +class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialState: RoomPermissionsViewState, + private val session: Session) + : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: RoomPermissionsViewState): RoomPermissionsViewModel + } + + companion object : MvRxViewModelFactory { + + @JvmStatic + override fun create(viewModelContext: ViewModelContext, state: RoomPermissionsViewState): RoomPermissionsViewModel? { + val fragment: RoomPermissionsFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.viewModelFactory.create(state) + } + } + + private val room = session.getRoom(initialState.roomId)!! + + init { + observeRoomSummary() + observePowerLevel() + } + + private fun observeRoomSummary() { + room.rx().liveRoomSummary() + .unwrap() + .execute { async -> + copy( + roomSummary = async + ) + } + } + + private fun observePowerLevel() { + PowerLevelsObservableFactory(room) + .createObservable() + .subscribe { powerLevelContent -> + val powerLevelsHelper = PowerLevelsHelper(powerLevelContent) + val permissions = RoomPermissionsViewState.ActionPermissions( + canChangePowerLevels = powerLevelsHelper.isUserAllowedToSend( + userId = session.myUserId, + isState = true, + eventType = EventType.STATE_ROOM_POWER_LEVELS + ) + ) + setState { + copy( + actionPermissions = permissions, + currentPowerLevelsContent = Success(powerLevelContent) + ) + } + } + .disposeOnClear() + } + + override fun handle(action: RoomPermissionsAction) { + when (action) { + is RoomPermissionsAction.UpdatePermission -> updatePermission(action) + }.exhaustive + } + + private fun updatePermission(action: RoomPermissionsAction.UpdatePermission) { + withState { state -> + val currentPowerLevel = state.currentPowerLevelsContent.invoke() ?: return@withState + postLoading(true) + viewModelScope.launch { + try { + val newPowerLevelsContent = when(action.editablePermission) { + is EditablePermission.EventTypeEditablePermission -> currentPowerLevel.copy( + events = currentPowerLevel.events.toMutableMap().apply { + put(action.editablePermission.eventType, action.powerLevel) + } + ) + is EditablePermission.DefaultRole -> currentPowerLevel.copy(usersDefault = action.powerLevel) + is EditablePermission.SendMessages -> currentPowerLevel.copy(eventsDefault = action.powerLevel) + is EditablePermission.InviteUsers -> currentPowerLevel.copy(invite = action.powerLevel) + is EditablePermission.ChangeSettings -> currentPowerLevel.copy(stateDefault = action.powerLevel) + is EditablePermission.KickUsers -> currentPowerLevel.copy(kick = action.powerLevel) + is EditablePermission.BanUsers -> currentPowerLevel.copy(ban = action.powerLevel) + is EditablePermission.RemoveMessagesSentByOthers -> currentPowerLevel.copy(redact = action.powerLevel) + is EditablePermission.NotifyEveryone -> currentPowerLevel.copy( + notifications = currentPowerLevel.notifications.toMutableMap().apply { + put("room", action.powerLevel) + } + ) + } + room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent.toContent()) + setState { + copy( + isLoading = false + ) + } + } catch (failure: Throwable) { + postLoading(false) + _viewEvents.post(RoomPermissionsViewEvents.Failure(failure)) + } + } + } + } + + private fun postLoading(isLoading: Boolean) { + setState { + copy(isLoading = isLoading) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt new file mode 100644 index 0000000000..556c44b730 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2021 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.app.features.roomprofile.permissions + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized +import im.vector.app.features.roomprofile.RoomProfileArgs +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.model.RoomSummary + +data class RoomPermissionsViewState( + val roomId: String, + val roomSummary: Async = Uninitialized, + val actionPermissions: ActionPermissions = ActionPermissions(), + val currentPowerLevelsContent: Async = Uninitialized, + val newPowerLevelsContent: PowerLevelsContent? = null, + val isLoading: Boolean = false +) : MvRxState { + + constructor(args: RoomProfileArgs) : this(roomId = args.roomId) + + data class ActionPermissions( + val canChangePowerLevels: Boolean = false + ) +} diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index bf3c1f87f8..1984be078d 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -46,6 +46,7 @@ class RoomSettingsController @Inject constructor( fun onTopicChanged(topic: String) fun onHistoryVisibilityClicked() fun onRoomAliasesClicked() + fun onRoomPermissionsClicked() fun onJoinRuleClicked() } @@ -115,6 +116,16 @@ class RoomSettingsController @Inject constructor( action = { callback?.onRoomAliasesClicked() } ) + buildProfileAction( + id = "permissions", + title = stringProvider.getString(R.string.room_settings_permissions_title), + subtitle = stringProvider.getString(R.string.room_settings_permissions_subtitle), + dividerColor = dividerColor, + divider = true, + editable = true, + action = { callback?.onRoomPermissionsClicked() } + ) + buildProfileAction( id = "historyReadability", title = stringProvider.getString(R.string.room_settings_room_read_history_rules_pref_title), diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index 52e273f3d4..1ca539ea7e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -178,6 +178,10 @@ class RoomSettingsFragment @Inject constructor( roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomAliasesSettings) } + override fun onRoomPermissionsClicked() { + roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomPermissionsSettings) + } + override fun onJoinRuleClicked() = withState(viewModel) { state -> val currentJoinRule = state.newRoomJoinRules.newJoinRules ?: state.currentRoomJoinRules val currentGuestAccess = state.newRoomJoinRules.newGuestAccess ?: state.currentGuestAccess diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 355ac4d6d6..467270b58e 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -609,6 +609,32 @@ The certificate has changed from a previously trusted one to one that is not trusted. The server may have renewed its certificate. Contact the server administrator for the expected fingerprint. Only accept the certificate if the server administrator has published a fingerprint that matches the one above. + + Room permissions + View and update the roles required to change various parts of the room. + + "Permissions" + "Select the roles required to change various parts of the room" + + Default role + Send messages + Invite users + Change settings + Kick users + Ban users + Remove messages sent by others + Notify everyone + Modify widgets + Change room avatar + Change main address for the room + Enable room encryption + Change history visibility + Change room name + Change permissions + Send m.room.server_acl events + Upgrade the room + Change topic + Room Details People From 0702eee179489a592c20fa227508c6c0e8fb2ad8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Jan 2021 18:38:06 +0100 Subject: [PATCH 144/224] Improve code --- .../SenderNotificationPermissionCondition.kt | 2 +- .../session/room/model/PowerLevelsContent.kt | 19 +++++++++++++++++++ .../room/powerlevels/PowerLevelsHelper.kt | 15 --------------- .../permissions/RoomPermissionsController.kt | 2 +- .../permissions/RoomPermissionsViewModel.kt | 3 ++- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt index 4f9c84a47c..6675fb0ff5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt @@ -37,6 +37,6 @@ class SenderNotificationPermissionCondition( fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean { val powerLevelsHelper = PowerLevelsHelper(powerLevels) - return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevelsHelper.notificationLevel(key) + return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevels.notificationLevel(key) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt index c466486ec0..317948388d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt @@ -53,4 +53,23 @@ data class PowerLevelsContent( } ) } + + /** + * Get the notification level for a dedicated key. + * + * @param key the notification key + * @return the level, default to Moderator if the key is not found + */ + fun notificationLevel(key: String): Int { + return when (val value = notifications[key]) { + // the first implementation was a string value + is String -> value.toInt() + is Int -> value + else -> Role.Moderator.value + } + } + + companion object { + const val NOTIFICATIONS_ROOM_KEY = "room" + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt index 47922f6968..4f1253c6df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt @@ -108,19 +108,4 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) { val powerLevel = getUserPowerLevelValue(userId) return powerLevel >= powerLevelsContent.redact } - - /** - * Get the notification level for a dedicated key. - * - * @param key the notification key - * @return the level - */ - fun notificationLevel(key: String): Int { - return when (val value = powerLevelsContent.notifications[key]) { - // the first implementation was a string value - is String -> value.toInt() - is Int -> value - else -> Role.Moderator.value - } - } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt index 058f5a9ce7..399ada62f6 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt @@ -123,7 +123,7 @@ class RoomPermissionsController @Inject constructor( is EditablePermission.KickUsers -> content.kick is EditablePermission.BanUsers -> content.ban is EditablePermission.RemoveMessagesSentByOthers -> content.redact - is EditablePermission.NotifyEveryone -> (content.notifications["room"] as? Int) ?: Role.Moderator.value + is EditablePermission.NotifyEveryone -> content.notificationLevel(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY) } return Role.fromValue( diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt index 95217c1885..af0a392d88 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.unwrap @@ -118,7 +119,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat is EditablePermission.RemoveMessagesSentByOthers -> currentPowerLevel.copy(redact = action.powerLevel) is EditablePermission.NotifyEveryone -> currentPowerLevel.copy( notifications = currentPowerLevel.notifications.toMutableMap().apply { - put("room", action.powerLevel) + put(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY, action.powerLevel) } ) } From f253aa6b3721355f8b1293edccc95aabef2ea4f9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Jan 2021 18:45:24 +0100 Subject: [PATCH 145/224] Remove unused field --- .../features/roomprofile/permissions/RoomPermissionsViewState.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt index 556c44b730..47c82bde2a 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt @@ -28,7 +28,6 @@ data class RoomPermissionsViewState( val roomSummary: Async = Uninitialized, val actionPermissions: ActionPermissions = ActionPermissions(), val currentPowerLevelsContent: Async = Uninitialized, - val newPowerLevelsContent: PowerLevelsContent? = null, val isLoading: Boolean = false ) : MvRxState { From 81bdf506bcdcee1a12120e5b6dd866652accb7d6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Jan 2021 22:45:40 +0100 Subject: [PATCH 146/224] Fix Int type issue when sending PowerLevelsContent to the server --- .../session/room/model/PowerLevelsContent.kt | 1 + .../session/room/state/DefaultStateService.kt | 14 +++-- .../room/state/SafePowerLevelContent.kt | 60 +++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt index 317948388d..e18cb7f05f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt @@ -64,6 +64,7 @@ data class PowerLevelsContent( return when (val value = notifications[key]) { // the first implementation was a string value is String -> value.toInt() + is Double -> value.toInt() is Int -> value else -> Role.Moderator.value } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt index b546584450..804968bac0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt @@ -35,13 +35,11 @@ import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.MimeTypes import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.session.content.FileUploader -import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String, private val stateEventDataSource: StateEventDataSource, private val sendStateTask: SendStateTask, - private val fileUploader: FileUploader, - private val addRoomAliasTask: AddRoomAliasTask + private val fileUploader: FileUploader ) : StateService { @AssistedInject.Factory @@ -74,11 +72,19 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private roomId = roomId, stateKey = stateKey, eventType = eventType, - body = body + body = body.toSafeJson(eventType) ) sendStateTask.execute(params) } + private fun JsonDict.toSafeJson(eventType: String): JsonDict { + // Safe treatment for PowerLevelContent + return when (eventType) { + EventType.STATE_ROOM_POWER_LEVELS -> toSafePowerLevelsContentDict() + else -> this + } + } + override suspend fun updateTopic(topic: String) { sendStateEvent( eventType = EventType.STATE_ROOM_TOPIC, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt new file mode 100644 index 0000000000..9f9a63de84 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 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 org.matrix.android.sdk.internal.session.room.state + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.powerlevels.Role +import org.matrix.android.sdk.api.util.JsonDict + +@JsonClass(generateAdapter = true) +internal data class SerializablePowerLevelsContent( + @Json(name = "ban") val ban: Int = Role.Moderator.value, + @Json(name = "kick") val kick: Int = Role.Moderator.value, + @Json(name = "invite") val invite: Int = Role.Moderator.value, + @Json(name = "redact") val redact: Int = Role.Moderator.value, + @Json(name = "events_default") val eventsDefault: Int = Role.Default.value, + @Json(name = "events") val events: Map = emptyMap(), + @Json(name = "users_default") val usersDefault: Int = Role.Default.value, + @Json(name = "users") val users: Map = emptyMap(), + @Json(name = "state_default") val stateDefault: Int = Role.Moderator.value, + // `Int` is the diff here (instead of `Any`) + @Json(name = "notifications") val notifications: Map = emptyMap() +) + +internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict { + return toModel() + ?.let { content -> + SerializablePowerLevelsContent( + ban = content.ban, + kick = content.kick, + invite = content.invite, + redact = content.redact, + eventsDefault = content.eventsDefault, + events = content.events, + usersDefault = content.usersDefault, + users = content.users, + stateDefault = content.stateDefault, + notifications = content.notifications.mapValues { content.notificationLevel(it.key) } + ) + } + ?.toContent() + ?: emptyMap() +} From a28dfdc48ea66f21d6e731a22c72d3172e4d1e35 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Jan 2021 23:03:09 +0100 Subject: [PATCH 147/224] Improve UI and UX when permission are not editable --- .../permissions/RoomPermissionsController.kt | 17 +++++++++++------ vector/src/main/res/values/strings.xml | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt index 399ada62f6..313782bf28 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt @@ -73,11 +73,6 @@ class RoomPermissionsController @Inject constructor( stringProvider.getString(R.string.room_permissions_title) ) - settingsInfoItem { - id("notice") - helperText(stringProvider.getString(R.string.room_permissions_notice)) - } - when (val content = data?.currentPowerLevelsContent) { is Success -> buildPermissions(data, content()) else -> { @@ -90,6 +85,12 @@ class RoomPermissionsController @Inject constructor( } private fun buildPermissions(data: RoomPermissionsViewState, content: PowerLevelsContent) { + val editable = data.actionPermissions.canChangePowerLevels + settingsInfoItem { + id("notice") + helperText(stringProvider.getString(if (editable) R.string.room_permissions_notice else R.string.room_permissions_notice_read_only)) + } + allEditablePermissions.forEach { editablePermission -> val currentRole = getCurrentRole(editablePermission, content) buildProfileAction( @@ -99,7 +100,11 @@ class RoomPermissionsController @Inject constructor( dividerColor = dividerColor, divider = true, editable = data.actionPermissions.canChangePowerLevels, - action = { callback?.onEditPermission(editablePermission, currentRole) } + action = { + callback + ?.takeIf { editable } + ?.onEditPermission(editablePermission, currentRole) + } ) } } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 467270b58e..b352d67490 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -615,6 +615,7 @@ "Permissions" "Select the roles required to change various parts of the room" + "You don't have permission to update the roles required to change various parts of the room" Default role Send messages From 037e53f385d7c66ef85f52181f26baf5c2290c5c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Jan 2021 23:24:25 +0100 Subject: [PATCH 148/224] Split permissions between useful ones and the others --- .../permissions/RoomPermissionsAction.kt | 2 + .../permissions/RoomPermissionsController.kt | 75 +++++++++++++------ .../permissions/RoomPermissionsFragment.kt | 4 + .../permissions/RoomPermissionsViewModel.kt | 9 ++- .../permissions/RoomPermissionsViewState.kt | 1 + 5 files changed, 66 insertions(+), 25 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt index 32d9236fb6..b853dda160 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsAction.kt @@ -19,5 +19,7 @@ package im.vector.app.features.roomprofile.permissions import im.vector.app.core.platform.VectorViewModelAction sealed class RoomPermissionsAction : VectorViewModelAction { + object ToggleShowAllPermissions : RoomPermissionsAction() + data class UpdatePermission(val editablePermission: EditablePermission, val powerLevel: Int) : RoomPermissionsAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt index 313782bf28..92bdac7ae0 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsController.kt @@ -25,6 +25,7 @@ import im.vector.app.core.epoxy.profiles.buildProfileSection import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider import im.vector.app.features.discovery.settingsInfoItem +import im.vector.app.features.form.formAdvancedToggleItem import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.powerlevels.Role import javax.inject.Inject @@ -36,6 +37,7 @@ class RoomPermissionsController @Inject constructor( interface Callback { fun onEditPermission(editablePermission: EditablePermission, currentRole: Role) + fun toggleShowAllPermissions() } var callback: Callback? = null @@ -43,25 +45,34 @@ class RoomPermissionsController @Inject constructor( private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color) // Order is the order applied in the UI - private val allEditablePermissions = listOf( + // Element Web order is not really nice, try to put the settings which are more likely to be updated first + // And a second section, hidden by default + private val usefulEditablePermissions = listOf( + EditablePermission.ChangeRoomAvatar(), + EditablePermission.ChangeRoomName(), + EditablePermission.ChangeTopic() + ) + + private val advancedEditablePermissions = listOf( + EditablePermission.ChangeMainAddressForTheRoom(), + EditablePermission.DefaultRole(), - EditablePermission.SendMessages(), EditablePermission.InviteUsers(), - EditablePermission.ChangeSettings(), EditablePermission.KickUsers(), EditablePermission.BanUsers(), + + EditablePermission.SendMessages(), + EditablePermission.RemoveMessagesSentByOthers(), EditablePermission.NotifyEveryone(), + + EditablePermission.ChangeSettings(), EditablePermission.ModifyWidgets(), - EditablePermission.ChangeRoomAvatar(), - EditablePermission.ChangeMainAddressForTheRoom(), - EditablePermission.EnableRoomEncryption(), EditablePermission.ChangeHistoryVisibility(), - EditablePermission.ChangeRoomName(), EditablePermission.ChangePermissions(), EditablePermission.SendRoomServerAclEvents(), - EditablePermission.UpgradeTheRoom(), - EditablePermission.ChangeTopic() + EditablePermission.EnableRoomEncryption(), + EditablePermission.UpgradeTheRoom() ) init { @@ -91,22 +102,38 @@ class RoomPermissionsController @Inject constructor( helperText(stringProvider.getString(if (editable) R.string.room_permissions_notice else R.string.room_permissions_notice_read_only)) } - allEditablePermissions.forEach { editablePermission -> - val currentRole = getCurrentRole(editablePermission, content) - buildProfileAction( - id = editablePermission.labelResId.toString(), - title = stringProvider.getString(editablePermission.labelResId), - subtitle = getSubtitle(currentRole), - dividerColor = dividerColor, - divider = true, - editable = data.actionPermissions.canChangePowerLevels, - action = { - callback - ?.takeIf { editable } - ?.onEditPermission(editablePermission, currentRole) - } - ) + // Useful permissions + usefulEditablePermissions.forEach { buildPermission(it, content, editable) } + + // Toggle + formAdvancedToggleItem { + id("showAdvanced") + title(stringProvider.getString(if (data.showAdvancedPermissions) R.string.hide_advanced else R.string.show_advanced)) + expanded(!data.showAdvancedPermissions) + listener { callback?.toggleShowAllPermissions() } } + + // Advanced permissions + if (data.showAdvancedPermissions) { + advancedEditablePermissions.forEach { buildPermission(it, content, editable) } + } + } + + private fun buildPermission(editablePermission: EditablePermission, content: PowerLevelsContent, editable: Boolean) { + val currentRole = getCurrentRole(editablePermission, content) + buildProfileAction( + id = editablePermission.labelResId.toString(), + title = stringProvider.getString(editablePermission.labelResId), + subtitle = getSubtitle(currentRole), + dividerColor = dividerColor, + divider = true, + editable = editable, + action = { + callback + ?.takeIf { editable } + ?.onEditPermission(editablePermission, currentRole) + } + ) } private fun getSubtitle(currentRole: Role): String { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt index 73e0b00de9..61635c9b31 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt @@ -99,4 +99,8 @@ class RoomPermissionsFragment @Inject constructor( viewModel.handle(RoomPermissionsAction.UpdatePermission(editablePermission, newPowerLevel)) } } + + override fun toggleShowAllPermissions() { + viewModel.handle(RoomPermissionsAction.ToggleShowAllPermissions) + } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt index af0a392d88..12f2467247 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt @@ -94,10 +94,17 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat override fun handle(action: RoomPermissionsAction) { when (action) { - is RoomPermissionsAction.UpdatePermission -> updatePermission(action) + is RoomPermissionsAction.UpdatePermission -> updatePermission(action) + RoomPermissionsAction.ToggleShowAllPermissions -> toggleShowAllPermissions() }.exhaustive } + private fun toggleShowAllPermissions() { + setState { + copy(showAdvancedPermissions = !showAdvancedPermissions) + } + } + private fun updatePermission(action: RoomPermissionsAction.UpdatePermission) { withState { state -> val currentPowerLevel = state.currentPowerLevelsContent.invoke() ?: return@withState diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt index 47c82bde2a..ce38ab87e5 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt @@ -27,6 +27,7 @@ data class RoomPermissionsViewState( val roomId: String, val roomSummary: Async = Uninitialized, val actionPermissions: ActionPermissions = ActionPermissions(), + val showAdvancedPermissions: Boolean = false, val currentPowerLevelsContent: Async = Uninitialized, val isLoading: Boolean = false ) : MvRxState { From ae55ee82a7b6a634749466244073c345cac8decd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Jan 2021 00:07:40 +0100 Subject: [PATCH 149/224] Cleanup --- .../sdk/internal/session/room/state/SafePowerLevelContent.kt | 2 +- .../roomprofile/permissions/RoomPermissionsViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt index 9f9a63de84..a97709e38b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 New Vector Ltd + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt index 12f2467247..183488a5e0 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt @@ -111,7 +111,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat postLoading(true) viewModelScope.launch { try { - val newPowerLevelsContent = when(action.editablePermission) { + val newPowerLevelsContent = when (action.editablePermission) { is EditablePermission.EventTypeEditablePermission -> currentPowerLevel.copy( events = currentPowerLevel.events.toMutableMap().apply { put(action.editablePermission.eventType, action.powerLevel) From a6f909b942538f2549da847492b2e9b5818133ab Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Jan 2021 11:04:11 +0100 Subject: [PATCH 150/224] Add Javadoc --- .../session/room/model/PowerLevelsContent.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt index e18cb7f05f..e778f5740d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt @@ -25,15 +25,45 @@ import org.matrix.android.sdk.api.session.room.powerlevels.Role */ @JsonClass(generateAdapter = true) data class PowerLevelsContent( + /** + * The level required to ban a user. Defaults to 50 if unspecified. + */ @Json(name = "ban") val ban: Int = Role.Moderator.value, + /** + * The level required to kick a user. Defaults to 50 if unspecified. + */ @Json(name = "kick") val kick: Int = Role.Moderator.value, + /** + * The level required to invite a user. Defaults to 50 if unspecified. + */ @Json(name = "invite") val invite: Int = Role.Moderator.value, + /** + * The level required to redact an event. Defaults to 50 if unspecified. + */ @Json(name = "redact") val redact: Int = Role.Moderator.value, + /** + * The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified. + */ @Json(name = "events_default") val eventsDefault: Int = Role.Default.value, + /** + * The level required to send specific event types. This is a mapping from event type to power level required. + */ @Json(name = "events") val events: Map = emptyMap(), + /** + * The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified. + */ @Json(name = "users_default") val usersDefault: Int = Role.Default.value, + /** + * The power levels for specific users. This is a mapping from user_id to power level for that user. + */ @Json(name = "users") val users: Map = emptyMap(), + /** + * The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified. + */ @Json(name = "state_default") val stateDefault: Int = Role.Moderator.value, + /** + * The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key. + */ @Json(name = "notifications") val notifications: Map = emptyMap() ) { /** @@ -71,6 +101,9 @@ data class PowerLevelsContent( } companion object { + /** + * Key to use for content.notifications and get the level required to trigger an @room notification. Defaults to 50 if unspecified. + */ const val NOTIFICATIONS_ROOM_KEY = "room" } } From afa1cf7d6c46c944672dda05f58143940ef97b71 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 7 Jan 2021 11:18:05 +0100 Subject: [PATCH 151/224] Cleaning --- .../internal/crypto/store/db/RealmCryptoStoreMigration.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt index 257e70936c..bca7914388 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -490,9 +490,9 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi private fun migrateTo12(realm: DynamicRealm) { Timber.d("Step 11 -> 12") val outboundEntitySchema = realm.schema.create("OutboundGroupSessionInfoEntity") - ?.addField(OutboundGroupSessionInfoEntityFields.SERIALIZED_OUTBOUND_SESSION_DATA, String::class.java) - ?.addField(OutboundGroupSessionInfoEntityFields.CREATION_TIME, Long::class.java) - ?.setNullable(OutboundGroupSessionInfoEntityFields.CREATION_TIME, true) + .addField(OutboundGroupSessionInfoEntityFields.SERIALIZED_OUTBOUND_SESSION_DATA, String::class.java) + .addField(OutboundGroupSessionInfoEntityFields.CREATION_TIME, Long::class.java) + .setNullable(OutboundGroupSessionInfoEntityFields.CREATION_TIME, true) realm.schema.get("CryptoRoomEntity") ?.addRealmObjectField(CryptoRoomEntityFields.OUTBOUND_SESSION_INFO.`$`, outboundEntitySchema) From 75e06d43c565fe8676e656f2d8eac79aa0afa35e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 7 Jan 2021 12:29:34 +0100 Subject: [PATCH 152/224] Cover room settings screens by the sanity unit test --- .../vector/app/ui/UiAllScreensSanityTest.kt | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt index cc4724e8f3..58b596b05f 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt @@ -247,6 +247,7 @@ class UiAllScreensSanityTest { // Room settings clickListItem(R.id.matrixProfileRecyclerView, 3) + navigateToRoomParameters() pressBack() // Notifications @@ -285,6 +286,31 @@ class UiAllScreensSanityTest { pressBack() } + private fun navigateToRoomParameters() { + // Room addresses + clickListItem(R.id.roomSettingsRecyclerView, 4) + onView(isRoot()).perform(waitForView(withText(R.string.room_alias_published_alias_title))) + pressBack() + + // Room permissions + clickListItem(R.id.roomSettingsRecyclerView, 6) + onView(isRoot()).perform(waitForView(withText(R.string.room_permissions_title))) + clickOn(R.string.room_permissions_change_room_avatar) + clickDialogNegativeButton() + // Toggle + clickOn(R.string.show_advanced) + clickOn(R.string.hide_advanced) + pressBack() + + // Room history readability + clickListItem(R.id.roomSettingsRecyclerView, 8) + pressBack() + + // Room access + clickListItem(R.id.roomSettingsRecyclerView, 10) + pressBack() + } + private fun navigateToInvite() { assertDisplayed(R.id.inviteUsersButton) clickOn(R.id.inviteUsersButton) From 55f5f90c45b060cbf25565b0b9969a91c3ed7324 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 7 Jan 2021 19:32:04 +0300 Subject: [PATCH 153/224] Use ContentResolver and DocumentFile instead of legacy File. Fixes #409. --- CHANGES.md | 1 + .../vector/app/core/glide/MyAppGlideModule.kt | 2 +- .../app/core/glide/VectorGlideModelLoader.kt | 24 ++++++++++++------- .../im/vector/app/core/utils/FileUtils.kt | 16 ++++++++++++- .../timeline/factory/MessageItemFactory.kt | 12 ++++++---- .../timeline/item/MessageImageVideoItem.kt | 3 ++- .../features/media/ImageContentRenderer.kt | 7 +++--- .../features/media/VideoContentRenderer.kt | 8 ++++--- 8 files changed, 51 insertions(+), 22 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7d4678fe40..a92a0e6d09 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ Bugfix 🐛: - Url previews sometimes attached to wrong message (#2561) - Hiding membership events works the exact opposite (#2603) - Tapping drawer having more than 1 room in notifications gives "malformed link" error (#2605) + - Sent image not displayed when opened immediately after sending (#409) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt index a51410165b..d73c64b087 100644 --- a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt +++ b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt @@ -38,6 +38,6 @@ class MyAppGlideModule : AppGlideModule() { override fun registerComponents(context: Context, glide: Glide, registry: Registry) { registry.append(ImageContentRenderer.Data::class.java, InputStream::class.java, - VectorGlideModelLoaderFactory(context.vectorComponent().activeSessionHolder())) + VectorGlideModelLoaderFactory(context, context.vectorComponent().activeSessionHolder())) } } diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt index 9a7cf1eb76..600ed0317e 100644 --- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt @@ -16,6 +16,7 @@ package im.vector.app.core.glide +import android.content.Context import com.bumptech.glide.Priority import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.Options @@ -25,6 +26,8 @@ import com.bumptech.glide.load.model.ModelLoaderFactory import com.bumptech.glide.load.model.MultiModelLoaderFactory import com.bumptech.glide.signature.ObjectKey import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.utils.isLocalFile +import im.vector.app.core.utils.openInputStream import im.vector.app.features.media.ImageContentRenderer import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixCallback @@ -33,11 +36,12 @@ import java.io.File import java.io.IOException import java.io.InputStream -class VectorGlideModelLoaderFactory(private val activeSessionHolder: ActiveSessionHolder) - : ModelLoaderFactory { +class VectorGlideModelLoaderFactory(private val context: Context, + private val activeSessionHolder: ActiveSessionHolder +) : ModelLoaderFactory { override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { - return VectorGlideModelLoader(activeSessionHolder) + return VectorGlideModelLoader(context, activeSessionHolder) } override fun teardown() { @@ -45,7 +49,7 @@ class VectorGlideModelLoaderFactory(private val activeSessionHolder: ActiveSessi } } -class VectorGlideModelLoader(private val activeSessionHolder: ActiveSessionHolder) +class VectorGlideModelLoader(private val context: Context, private val activeSessionHolder: ActiveSessionHolder) : ModelLoader { override fun handles(model: ImageContentRenderer.Data): Boolean { // Always handle @@ -53,11 +57,12 @@ class VectorGlideModelLoader(private val activeSessionHolder: ActiveSessionHolde } override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData? { - return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(activeSessionHolder, model, width, height)) + return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(context, activeSessionHolder, model, width, height)) } } -class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolder, +class VectorGlideDataFetcher(private val context: Context, + private val activeSessionHolder: ActiveSessionHolder, private val data: ImageContentRenderer.Data, private val width: Int, private val height: Int) @@ -97,9 +102,10 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { Timber.v("Load data: $data") - if (data.isLocalFile && data.url != null) { - val initialFile = File(data.url) - callback.onDataReady(initialFile.inputStream()) + if (data.url.isLocalFile(context)) { + data.url.openInputStream(context)?.use { + callback.onDataReady(it) + } return } // val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() diff --git a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt index aa36dd0959..2be06c09a5 100644 --- a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt +++ b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt @@ -17,14 +17,28 @@ package im.vector.app.core.utils import android.content.Context +import android.net.Uri +import androidx.documentfile.provider.DocumentFile +import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber import java.io.File +import java.io.InputStream import java.util.Locale // Implementation should return true in case of success typealias ActionOnFile = (file: File) -> Boolean -internal fun String?.isLocalFile() = this != null && File(this).exists() +internal fun String?.isLocalFile(context: Context): Boolean { + return this?.let { + DocumentFile.fromSingleUri(context, Uri.parse(it))?.exists() + }.orFalse() +} + +internal fun String?.openInputStream(context: Context): InputStream? { + return if (isLocalFile(context)) { + context.contentResolver.openInputStream(Uri.parse(this)) + } else null +} /* ========================================================================================== * Delete diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index a1e041b98f..3dea83032c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -16,6 +16,7 @@ package im.vector.app.features.home.room.detail.timeline.factory +import android.content.Context import android.text.SpannableStringBuilder import android.text.Spanned import android.text.TextPaint @@ -94,6 +95,7 @@ import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import javax.inject.Inject class MessageItemFactory @Inject constructor( + private val context: Context, private val colorProvider: ColorProvider, private val dimensionConverter: DimensionConverter, private val timelineMediaSizeProvider: TimelineMediaSizeProvider, @@ -205,7 +207,7 @@ class MessageItemFactory @Inject constructor( } ?: "" return MessageFileItem_() .attributes(attributes) - .izLocalFile(fileUrl.isLocalFile()) + .izLocalFile(fileUrl.isLocalFile(context)) .izDownloaded(session.fileService().isFileInCache( fileUrl, messageContent.getFileName(), @@ -270,7 +272,7 @@ class MessageItemFactory @Inject constructor( return MessageFileItem_() .attributes(attributes) .leftGuideline(avatarSizeProvider.leftGuideline) - .izLocalFile(messageContent.getFileUrl().isLocalFile()) + .izLocalFile(messageContent.getFileUrl().isLocalFile(context)) .izDownloaded(session.fileService().isFileInCache(messageContent)) .mxcUrl(mxcUrl) .contentUploadStateTrackerBinder(contentUploadStateTrackerBinder) @@ -305,7 +307,8 @@ class MessageItemFactory @Inject constructor( height = messageContent.info?.height, maxHeight = maxHeight, width = messageContent.info?.width, - maxWidth = maxWidth + maxWidth = maxWidth, + allowNonMxcUrls = informationData.sendState.isSending() ) return MessageImageVideoItem_() .attributes(attributes) @@ -343,7 +346,8 @@ class MessageItemFactory @Inject constructor( height = messageContent.videoInfo?.height, maxHeight = maxHeight, width = messageContent.videoInfo?.width, - maxWidth = maxWidth + maxWidth = maxWidth, + allowNonMxcUrls = informationData.sendState.isSending() ) val videoData = VideoContentRenderer.Data( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index 98db0bc9b9..a8d5ed1631 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -26,6 +26,7 @@ import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R import im.vector.app.core.glide.GlideApp +import im.vector.app.core.utils.isLocalFile import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.app.features.media.ImageContentRenderer import org.matrix.android.sdk.api.session.room.send.SendState @@ -55,7 +56,7 @@ abstract class MessageImageVideoItem : AbsMessageItem Date: Thu, 7 Jan 2021 18:28:05 +0100 Subject: [PATCH 154/224] Move interface to correct location --- .../matrix/android/sdk/internal/network/GlobalErrorReceiver.kt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename matrix-sdk-android/src/{debug => main}/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt (100%) diff --git a/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt similarity index 100% rename from matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt From 003f5fab1f475e5e00e79926b727ff9ffc51767d Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Thu, 7 Jan 2021 19:44:32 +0000 Subject: [PATCH 155/224] Added translation using Weblate (Hebrew) --- vector/src/main/res/values-he/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vector/src/main/res/values-he/strings.xml diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml new file mode 100644 index 0000000000..a6b3daec93 --- /dev/null +++ b/vector/src/main/res/values-he/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From da33cbedda02320d9e90aa421a1abb7910cbf048 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 8 Jan 2021 12:23:02 +0100 Subject: [PATCH 156/224] Introduce LocalFilesHelper to avoid using the Context directly --- .../vector/app/core/files/LocalFilesHelper.kt | 41 +++++++++++++++++++ .../vector/app/core/glide/MyAppGlideModule.kt | 3 +- .../app/core/glide/VectorGlideModelLoader.kt | 19 ++++----- .../im/vector/app/core/utils/FileUtils.kt | 16 -------- .../timeline/factory/MessageItemFactory.kt | 9 ++-- .../timeline/item/MessageImageVideoItem.kt | 4 +- .../features/media/ImageContentRenderer.kt | 7 ++-- .../features/media/VideoContentRenderer.kt | 9 ++-- 8 files changed, 65 insertions(+), 43 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt diff --git a/vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt b/vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt new file mode 100644 index 0000000000..d9cf4fc484 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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.app.core.files + +import android.content.Context +import android.net.Uri +import androidx.documentfile.provider.DocumentFile +import org.matrix.android.sdk.api.extensions.orFalse +import java.io.InputStream +import javax.inject.Inject + +class LocalFilesHelper @Inject constructor(private val context: Context) { + fun isLocalFile(fileUri: String?): Boolean { + return fileUri + ?.let { Uri.parse(it) } + ?.let { DocumentFile.fromSingleUri(context, it) } + ?.exists() + .orFalse() + } + + fun openInputStream(fileUri: String?): InputStream? { + return fileUri + ?.takeIf { isLocalFile(it) } + ?.let { Uri.parse(it) } + ?.let { context.contentResolver.openInputStream(it) } + } +} diff --git a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt index d73c64b087..edd8de2f79 100644 --- a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt +++ b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt @@ -25,6 +25,7 @@ import com.bumptech.glide.Registry import com.bumptech.glide.annotation.GlideModule import com.bumptech.glide.module.AppGlideModule import im.vector.app.core.extensions.vectorComponent +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.features.media.ImageContentRenderer import java.io.InputStream @@ -38,6 +39,6 @@ class MyAppGlideModule : AppGlideModule() { override fun registerComponents(context: Context, glide: Glide, registry: Registry) { registry.append(ImageContentRenderer.Data::class.java, InputStream::class.java, - VectorGlideModelLoaderFactory(context, context.vectorComponent().activeSessionHolder())) + VectorGlideModelLoaderFactory(LocalFilesHelper(context), context.vectorComponent().activeSessionHolder())) } } diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt index 600ed0317e..3acbba6337 100644 --- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt @@ -16,7 +16,6 @@ package im.vector.app.core.glide -import android.content.Context import com.bumptech.glide.Priority import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.Options @@ -26,8 +25,7 @@ import com.bumptech.glide.load.model.ModelLoaderFactory import com.bumptech.glide.load.model.MultiModelLoaderFactory import com.bumptech.glide.signature.ObjectKey import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.core.utils.isLocalFile -import im.vector.app.core.utils.openInputStream +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.features.media.ImageContentRenderer import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixCallback @@ -36,12 +34,12 @@ import java.io.File import java.io.IOException import java.io.InputStream -class VectorGlideModelLoaderFactory(private val context: Context, +class VectorGlideModelLoaderFactory(private val localFilesHelper: LocalFilesHelper, private val activeSessionHolder: ActiveSessionHolder ) : ModelLoaderFactory { override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { - return VectorGlideModelLoader(context, activeSessionHolder) + return VectorGlideModelLoader(localFilesHelper, activeSessionHolder) } override fun teardown() { @@ -49,7 +47,8 @@ class VectorGlideModelLoaderFactory(private val context: Context, } } -class VectorGlideModelLoader(private val context: Context, private val activeSessionHolder: ActiveSessionHolder) +class VectorGlideModelLoader(private val localFilesHelper: LocalFilesHelper, + private val activeSessionHolder: ActiveSessionHolder) : ModelLoader { override fun handles(model: ImageContentRenderer.Data): Boolean { // Always handle @@ -57,11 +56,11 @@ class VectorGlideModelLoader(private val context: Context, private val activeSes } override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData? { - return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(context, activeSessionHolder, model, width, height)) + return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(localFilesHelper, activeSessionHolder, model, width, height)) } } -class VectorGlideDataFetcher(private val context: Context, +class VectorGlideDataFetcher(private val localFilesHelper: LocalFilesHelper, private val activeSessionHolder: ActiveSessionHolder, private val data: ImageContentRenderer.Data, private val width: Int, @@ -102,8 +101,8 @@ class VectorGlideDataFetcher(private val context: Context, override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { Timber.v("Load data: $data") - if (data.url.isLocalFile(context)) { - data.url.openInputStream(context)?.use { + if (localFilesHelper.isLocalFile(data.url)) { + localFilesHelper.openInputStream(data.url)?.use { callback.onDataReady(it) } return diff --git a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt index 2be06c09a5..b5ce922487 100644 --- a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt +++ b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt @@ -17,29 +17,13 @@ package im.vector.app.core.utils import android.content.Context -import android.net.Uri -import androidx.documentfile.provider.DocumentFile -import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber import java.io.File -import java.io.InputStream import java.util.Locale // Implementation should return true in case of success typealias ActionOnFile = (file: File) -> Boolean -internal fun String?.isLocalFile(context: Context): Boolean { - return this?.let { - DocumentFile.fromSingleUri(context, Uri.parse(it))?.exists() - }.orFalse() -} - -internal fun String?.openInputStream(context: Context): InputStream? { - return if (isLocalFile(context)) { - context.contentResolver.openInputStream(Uri.parse(this)) - } else null -} - /* ========================================================================================== * Delete * ========================================================================================== */ diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 3dea83032c..4f52fcb54c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -16,7 +16,6 @@ package im.vector.app.features.home.room.detail.timeline.factory -import android.content.Context import android.text.SpannableStringBuilder import android.text.Spanned import android.text.TextPaint @@ -27,12 +26,12 @@ import android.view.View import dagger.Lazy import im.vector.app.R import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.containsOnlyEmojis -import im.vector.app.core.utils.isLocalFile import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder @@ -95,7 +94,7 @@ import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import javax.inject.Inject class MessageItemFactory @Inject constructor( - private val context: Context, + private val localFilesHelper: LocalFilesHelper, private val colorProvider: ColorProvider, private val dimensionConverter: DimensionConverter, private val timelineMediaSizeProvider: TimelineMediaSizeProvider, @@ -207,7 +206,7 @@ class MessageItemFactory @Inject constructor( } ?: "" return MessageFileItem_() .attributes(attributes) - .izLocalFile(fileUrl.isLocalFile(context)) + .izLocalFile(localFilesHelper.isLocalFile(fileUrl)) .izDownloaded(session.fileService().isFileInCache( fileUrl, messageContent.getFileName(), @@ -272,7 +271,7 @@ class MessageItemFactory @Inject constructor( return MessageFileItem_() .attributes(attributes) .leftGuideline(avatarSizeProvider.leftGuideline) - .izLocalFile(messageContent.getFileUrl().isLocalFile(context)) + .izLocalFile(localFilesHelper.isLocalFile(messageContent.getFileUrl())) .izDownloaded(session.fileService().isFileInCache(messageContent)) .mxcUrl(mxcUrl) .contentUploadStateTrackerBinder(contentUploadStateTrackerBinder) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index a8d5ed1631..5d14178088 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -25,8 +25,8 @@ import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.core.glide.GlideApp -import im.vector.app.core.utils.isLocalFile import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.app.features.media.ImageContentRenderer import org.matrix.android.sdk.api.session.room.send.SendState @@ -56,7 +56,7 @@ abstract class MessageImageVideoItem : AbsMessageItem Date: Fri, 8 Jan 2021 12:27:40 +0100 Subject: [PATCH 157/224] Simplify signatures --- .../vector/app/core/glide/MyAppGlideModule.kt | 8 ++++---- .../app/core/glide/VectorGlideModelLoader.kt | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt index edd8de2f79..6ded33f823 100644 --- a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt +++ b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt @@ -24,8 +24,6 @@ import com.bumptech.glide.GlideBuilder import com.bumptech.glide.Registry import com.bumptech.glide.annotation.GlideModule import com.bumptech.glide.module.AppGlideModule -import im.vector.app.core.extensions.vectorComponent -import im.vector.app.core.files.LocalFilesHelper import im.vector.app.features.media.ImageContentRenderer import java.io.InputStream @@ -37,8 +35,10 @@ class MyAppGlideModule : AppGlideModule() { } override fun registerComponents(context: Context, glide: Glide, registry: Registry) { - registry.append(ImageContentRenderer.Data::class.java, + registry.append( + ImageContentRenderer.Data::class.java, InputStream::class.java, - VectorGlideModelLoaderFactory(LocalFilesHelper(context), context.vectorComponent().activeSessionHolder())) + VectorGlideModelLoaderFactory(context) + ) } } diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt index 3acbba6337..81e81bb78a 100644 --- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt @@ -16,6 +16,7 @@ package im.vector.app.core.glide +import android.content.Context import com.bumptech.glide.Priority import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.Options @@ -24,7 +25,7 @@ import com.bumptech.glide.load.model.ModelLoader import com.bumptech.glide.load.model.ModelLoaderFactory import com.bumptech.glide.load.model.MultiModelLoaderFactory import com.bumptech.glide.signature.ObjectKey -import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.extensions.vectorComponent import im.vector.app.core.files.LocalFilesHelper import im.vector.app.features.media.ImageContentRenderer import okhttp3.OkHttpClient @@ -34,12 +35,10 @@ import java.io.File import java.io.IOException import java.io.InputStream -class VectorGlideModelLoaderFactory(private val localFilesHelper: LocalFilesHelper, - private val activeSessionHolder: ActiveSessionHolder -) : ModelLoaderFactory { +class VectorGlideModelLoaderFactory(private val context: Context) : ModelLoaderFactory { override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { - return VectorGlideModelLoader(localFilesHelper, activeSessionHolder) + return VectorGlideModelLoader(context) } override fun teardown() { @@ -47,8 +46,7 @@ class VectorGlideModelLoaderFactory(private val localFilesHelper: LocalFilesHelp } } -class VectorGlideModelLoader(private val localFilesHelper: LocalFilesHelper, - private val activeSessionHolder: ActiveSessionHolder) +class VectorGlideModelLoader(private val context: Context) : ModelLoader { override fun handles(model: ImageContentRenderer.Data): Boolean { // Always handle @@ -56,17 +54,19 @@ class VectorGlideModelLoader(private val localFilesHelper: LocalFilesHelper, } override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData? { - return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(localFilesHelper, activeSessionHolder, model, width, height)) + return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(context, model, width, height)) } } -class VectorGlideDataFetcher(private val localFilesHelper: LocalFilesHelper, - private val activeSessionHolder: ActiveSessionHolder, +class VectorGlideDataFetcher(context: Context, private val data: ImageContentRenderer.Data, private val width: Int, private val height: Int) : DataFetcher { + private val localFilesHelper = LocalFilesHelper(context) + private val activeSessionHolder = context.vectorComponent().activeSessionHolder() + private val client = activeSessionHolder.getSafeActiveSession()?.getOkHttpClient() ?: OkHttpClient() override fun getDataClass(): Class { From d91ed2985d2a0b7c5b03ef0834d4c6ad0cf9c4be Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 8 Jan 2021 12:40:20 +0100 Subject: [PATCH 158/224] Sync: fix initial sync is not retried correctly when there is some network error. [#2632] --- CHANGES.md | 2 +- .../internal/session/sync/job/SyncService.kt | 24 ++++--- .../app/core/services/VectorSyncService.kt | 71 ++++++++----------- 3 files changed, 44 insertions(+), 53 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index bff1a7480e..8a69aea6fd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,7 +15,7 @@ Bugfix 🐛: - Room Topic not displayed correctly after visiting a link (#2551) - Hiding membership events works the exact opposite (#2603) - Tapping drawer having more than 1 room in notifications gives "malformed link" error (#2605) - + - Initial sync is not retried correctly when there is some network error. (#2632) Translations 🗣: - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index 6d100a71f9..9d854229df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -36,6 +36,7 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import timber.log.Timber +import java.net.SocketTimeoutException import java.util.concurrent.atomic.AtomicBoolean /** @@ -68,14 +69,12 @@ abstract class SyncService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Timber.i("## Sync: onStartCommand [$this] $intent with action: ${intent?.action}") - - // We should start we have to ensure we fulfill contract to show notification - // for foreground service (as per design for this service) - // TODO can we check if it's really in foreground - onStart(isInitialSync) when (intent?.action) { ACTION_STOP -> { Timber.i("## Sync: stop command received") + // We should start we have to ensure we fulfill contract to show notification + // for foreground service (as per design for this service) + onStart(isInitialSync) // If it was periodic we ensure that it will not reschedule itself preventReschedule = true // we don't want to cancel initial syncs, let it finish @@ -85,11 +84,12 @@ abstract class SyncService : Service() { } else -> { val isInit = initialize(intent) + onStart(isInitialSync) if (isInit) { periodic = intent?.getBooleanExtra(EXTRA_PERIODIC, false) ?: false val onNetworkBack = intent?.getBooleanExtra(EXTRA_NETWORK_BACK_RESTART, false) ?: false Timber.d("## Sync: command received, periodic: $periodic networkBack: $onNetworkBack") - if (onNetworkBack && !backgroundDetectionObserver.isInBackground) { + if (!isInitialSync && onNetworkBack && !backgroundDetectionObserver.isInBackground) { // the restart after network occurs while the app is in foreground // so just stop. It will be restarted when entering background preventReschedule = true @@ -165,10 +165,16 @@ abstract class SyncService : Service() { preventReschedule = true } if (throwable is Failure.NetworkConnection) { - // Network is off, no need to reschedule endless alarms :/ + // Timeout is not critical, so retry as soon as possible. + val retryDelay = if (isInitialSync || throwable.cause is SocketTimeoutException) { + 0 + } else { + syncDelaySeconds + } + // Network might be off, no need to reschedule endless alarms :/ preventReschedule = true - // Instead start a work to restart background sync when network is back - onNetworkError(sessionId ?: "", isInitialSync, syncTimeoutSeconds, syncDelaySeconds) + // Instead start a work to restart background sync when network is on + onNetworkError(sessionId ?: "", isInitialSync, syncTimeoutSeconds, retryDelay) } // JobCancellation could be caught here when onDestroy cancels the coroutine context if (isRunning.get()) stopMe() diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index bf78d5b7fb..0950bdf121 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -21,7 +21,6 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.os.Build -import androidx.core.content.ContextCompat.getSystemService import androidx.core.content.getSystemService import androidx.work.Constraints import androidx.work.Data @@ -49,22 +48,19 @@ class VectorSyncService : SyncService() { } } - fun newPeriodicIntent(context: Context, sessionId: String, timeoutSeconds: Int, delayInSeconds: Int): Intent { + fun newPeriodicIntent( + context: Context, + sessionId: String, + timeoutSeconds: Int, + delayInSeconds: Int, + networkBack: Boolean = false + ): Intent { return Intent(context, VectorSyncService::class.java).also { it.putExtra(EXTRA_SESSION_ID, sessionId) it.putExtra(EXTRA_TIMEOUT_SECONDS, timeoutSeconds) it.putExtra(EXTRA_PERIODIC, true) it.putExtra(EXTRA_DELAY_SECONDS, delayInSeconds) - } - } - - fun newPeriodicNetworkBackIntent(context: Context, sessionId: String, timeoutSeconds: Int, delayInSeconds: Int): Intent { - return Intent(context, VectorSyncService::class.java).also { - it.putExtra(EXTRA_SESSION_ID, sessionId) - it.putExtra(EXTRA_TIMEOUT_SECONDS, timeoutSeconds) - it.putExtra(EXTRA_PERIODIC, true) - it.putExtra(EXTRA_DELAY_SECONDS, delayInSeconds) - it.putExtra(EXTRA_NETWORK_BACK_RESTART, true) + it.putExtra(EXTRA_NETWORK_BACK_RESTART, networkBack) } } @@ -93,12 +89,12 @@ class VectorSyncService : SyncService() { } override fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { - reschedule(sessionId, timeout, delay) + rescheduleSyncService(sessionId, timeout, delay) } override fun onNetworkError(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { Timber.d("## Sync: A network error occured during sync") - val uploadWorkRequest: WorkRequest = + val rescheduleSyncWorkRequest: WorkRequest = OneTimeWorkRequestBuilder() .setInputData(Data.Builder() .putString("sessionId", sessionId) @@ -115,7 +111,7 @@ class VectorSyncService : SyncService() { Timber.d("## Sync: Schedule a work to restart service when network will be on") WorkManager .getInstance(applicationContext) - .enqueue(uploadWorkRequest) + .enqueue(rescheduleSyncWorkRequest) } override fun onDestroy() { @@ -128,42 +124,31 @@ class VectorSyncService : SyncService() { notificationManager.cancel(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE) } - private fun reschedule(sessionId: String, timeout: Int, delay: Int) { - val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - PendingIntent.getForegroundService(this, 0, newPeriodicIntent(this, sessionId, timeout, delay), 0) - } else { - PendingIntent.getService(this, 0, newPeriodicIntent(this, sessionId, timeout, delay), 0) - } - val firstMillis = System.currentTimeMillis() + delay * 1000L - val alarmMgr = getSystemService()!! - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) - } else { - alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) - } - } - class RestartWhenNetworkOn(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { val sessionId = inputData.getString("sessionId") ?: return Result.failure() val timeout = inputData.getInt("timeout", 6) val delay = inputData.getInt("delay", 60) - - val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - PendingIntent.getForegroundService(applicationContext, 0, newPeriodicNetworkBackIntent(applicationContext, sessionId, timeout, delay), 0) - } else { - PendingIntent.getService(applicationContext, 0, newPeriodicNetworkBackIntent(applicationContext, sessionId, timeout, delay), 0) - } - val firstMillis = System.currentTimeMillis() + delay * 1000L - val alarmMgr = getSystemService(applicationContext, AlarmManager::class.java)!! - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) - } else { - alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) - } + applicationContext.rescheduleSyncService(sessionId, timeout, delay, true) // Indicate whether the work finished successfully with the Result return Result.success() } } } + +private fun Context.rescheduleSyncService(sessionId: String, timeout: Int, delay: Int, networkBack: Boolean = false) { + val periodicIntent = VectorSyncService.newPeriodicIntent(this, sessionId, timeout, delay, networkBack) + val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + PendingIntent.getForegroundService(this, 0, periodicIntent, 0) + } else { + PendingIntent.getService(this, 0, periodicIntent, 0) + } + val firstMillis = System.currentTimeMillis() + delay * 1000L + val alarmMgr = getSystemService()!! + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) + } else { + alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) + } +} From 56e8325efe5832cb48a852abb98d6b058e61b295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Fri, 8 Jan 2021 13:19:44 +0000 Subject: [PATCH 159/224] Translated using Weblate (Hebrew) Currently translated at 6.4% (130 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 103 +++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index a6b3daec93..f17fcf3dfc 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -1,2 +1,103 @@ - \ No newline at end of file + + התראות + בית + הצלחה + שגיאה + אזהרה + אישור + השבת + העתק ללוח הגזירים + הסר פרסום + הוסף + העתק + סגור + סמן כ\'נקרא\' + תגובה מהירה + היסטורי + סמן הכל כ\'נקרא\' + חיפוש כללי + שיחת וידאו + שיחה קולית + האם אתה בטוח שברצונך לצאת מחשבונך\? + יציאה מהחשבון + פעולות + יציאה + נתק + להסיר + לקבל + יְרִידָה + סקירה + להתעלם + לְהַפִּיל + בוצע + לדלג + לְקַבֵּל + לא מקוון + להזמין + לשלוח בכל מקרה + תתקשר בכל מקרה + שיחות ועידה אינן נתמכות בחדרים מוצפנים + הסרת היישומון נכשלה + הוספת היישומון נכשלה + מידע על מושב + אתה לא יכול להתקשר עם עצמך, לחכות שהמשתתפים יקבלו את ההזמנה + אינך יכול להתקשר עם עצמך + לא ניתן להתחיל להתקשר + הפגישות משתמשות במדיניות האבטחה וההרשאה של Jitsi. כל האנשים שנמצאים כעת בחדר יראו הזמנה להצטרף בזמן שהפגישה שלך מתרחשת. + התחל פגישת שמע + התחל פגישת וידאו + ועידה כבר בעיצומה! + אין לך הרשאה להתחיל שיחה + אין לך הרשאה להתחיל שיחה בחדר זה + אין לך הרשאה להתחיל שיחת ועידה + אין לך הרשאה להתחיל שיחת ועידה בחדר זה + אתה זקוק להרשאה כדי להזמין כדי להתחיל כנס בחדר זה + בגלל הרשאות חסרות, פעולה זו אינה אפשרית. + בגלל הרשאות חסרות, ייתכן שחלק מהתכונות חסרות … + לא יכול להתחיל את השיחה, נסה שוב מאוחר יותר + וידאו + קול + שיחת ועידה מתמשכת. +\nהצטרף כ-% 1 $ s או% 2 $ s + התחל לצ\'וטט + אתחול + השהה + לנגן + שיחה פעילה + דווח על תוכן + התנתק + לבטל + אין + שנה שם + מחק + צפה במקור המפוענח + צפה במקור הדף + קישור קבוע + העבר + מאוחר יותר + ניקוי + דבר + שתף + הורדה + צטט + הסר + שלח שוב + שלח + הישאר + עזיבה + שמירה + ביטול + אוקיי + טוען… + רישיונות צד ג \' + תאבד את הגישה להודעות המוצפנות שלך אלא אם כן תגבה את המפתחות לפני היציאה. + גבה + האם אתה בטוח\? + השתמש בגיבוי מפתח + מגבה מקשים … + אני לא רוצה את ההודעות המוצפנות שלי + גיבוי מפתח מאובטח צריך להיות פעיל בכל ההפעלות שלך כדי למנוע אובדן גישה להודעות המוצפנות שלך. + גיבוי המפתח מתבצע. אם תצא עכשיו תאבד את הגישה להודעות המוצפנות שלך. + אם תצא עכשיו, תאבד את ההודעות המוצפנות שלך + \ No newline at end of file From cf0242f23a25111959a76181eec8f6d78b623a17 Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Fri, 8 Jan 2021 13:19:28 +0000 Subject: [PATCH 160/224] Translated using Weblate (Hebrew) Currently translated at 6.4% (130 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index f17fcf3dfc..13ae15c86f 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -100,4 +100,33 @@ גיבוי מפתח מאובטח צריך להיות פעיל בכל ההפעלות שלך כדי למנוע אובדן גישה להודעות המוצפנות שלך. גיבוי המפתח מתבצע. אם תצא עכשיו תאבד את הגישה להודעות המוצפנות שלך. אם תצא עכשיו, תאבד את ההודעות המוצפנות שלך + קישור למטריקס + או + פתיחה + כניסה + שחרר + גיבוי המפתחות לא הסתיים, אנא המתן … + אמת מושב + השתמש במפתח גיבוי + גיבוי מפתח + שלח מדבקה + פרטי קהילה + דיווח תקלות + הסטוריה + פרטי משתמש + הגדרות + חדר + הודעות + התראות שקטות + התראות רועשות + האזנה לאירועים + מסנכרן… + אתחול השירות + ערכת נושא Status.im + ערכת נושא שחורה + ערכת נושא כהה + ערכת נושא בהירה + לטינית + ארה\"ב + אנגלית \ No newline at end of file From 6b605b2e980c9c91f1115c6ef74365a503ba7d9f Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Fri, 8 Jan 2021 13:23:56 +0000 Subject: [PATCH 161/224] Translated using Weblate (Hebrew) Currently translated at 7.4% (150 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 13ae15c86f..a1e7e87cf7 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -1,7 +1,7 @@ התראות - בית + כפתורי ניווט תחתונים הצלחה שגיאה אזהרה @@ -129,4 +129,15 @@ לטינית ארה\"ב אנגלית + + משתמש %d + %d משתמשים + מעט + אחר + + אין חדרים ציבורים + אין חדרים + רשימת חדרים + חדרים + אין שיחות \ No newline at end of file From 9d7c49306ab49b8f1ff2fcdce5a0ce70303313fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Fri, 8 Jan 2021 13:23:50 +0000 Subject: [PATCH 162/224] Translated using Weblate (Hebrew) Currently translated at 7.4% (150 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index a1e7e87cf7..a16f493e7b 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -140,4 +140,18 @@ רשימת חדרים חדרים אין שיחות + אנשי קשר מטריקס בלבד + תיקיית האב של המשתמש + פנקס כתובות מקומי + שיחות + התראות מערכת + בעדיפות נמוכה + הזמנות + סנן שמות מבין רשימת הקהילות + סנן מבין רשימת החדרים + סנן מבין רשימת האנשים + סנן מהמועדפים + סנן שמות חדרים + קהילות + חדרים \ No newline at end of file From 38e4984a4a79595d810ae9938adc1bd22eae517e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Fri, 8 Jan 2021 13:31:26 +0000 Subject: [PATCH 163/224] Translated using Weblate (Hebrew) Currently translated at 9.2% (187 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index a16f493e7b..f9e718f863 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -154,4 +154,8 @@ סנן שמות חדרים קהילות חדרים + לא הוגדר שרת זהות. + אין תוצאות נוספות + אין תוצאות + לא אפשרת לאלמנט לגשת לאנשי הקשר המקומיים שלך \ No newline at end of file From 1762451bc0556061a8603066d961411fd4ce2043 Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Fri, 8 Jan 2021 13:31:10 +0000 Subject: [PATCH 164/224] Translated using Weblate (Hebrew) Currently translated at 9.2% (187 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index f9e718f863..ac4e963fd6 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -158,4 +158,37 @@ אין תוצאות נוספות אין תוצאות לא אפשרת לאלמנט לגשת לאנשי הקשר המקומיים שלך + האם אתה בטוח שברצונך להתחיל צ\'אט חדש עם %s\? + שלח קול + התחל שיחת וידאו + התחל שיחה קולית + התחל צ\'אט חדש + חיפוש + קישור לשרת הזיהוי + קישור לשרת הבית + יציאה + כניסה + צור חשבון + שם משתמש + הצתרף אל חדר + קרא + שלח פנימה + התקדמות (%%%) + לא ניתן היה לשלוח את דוח הבאג (%s) + דוח הבאג נשלח בהצלחה + טלטול זעם כדי לדווח על באג + היישום התרסק בפעם האחרונה. האם ברצונך לפתוח את מסך דוח הקריסה\? + נראה שאתה מטלטל את הטלפון בתסכול. האם ברצונך לפתוח את מסך דוח הבאג\? + על מנת לאבחן בעיות, יומני הלקוח יישלחו עם דוח הבאג הזה. דוח באגים זה, כולל היומנים וצילום המסך, לא יהיה גלוי לציבור. אם אתה מעדיף לשלוח רק את הטקסט למעלה, בטל את הסימון: + תאר את הבעיה שלך כאן + אם אפשר, אנא כתוב את התיאור באנגלית. + אנא תאר את הבאג. מה עשית\? מה ציפית שיקרה\? מה באמת קרה\? + דווח על באג + שלח צילום מסך + שלח היסטוריית בקשות לשיתוף מפתח + שלח יומני תקלות + שלח יומנים + אין קבוצות + קהילות + הזמנה \ No newline at end of file From 2578423c9188bac1ab3dabb87e8d07704d8ce67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Fri, 8 Jan 2021 13:49:58 +0000 Subject: [PATCH 165/224] Translated using Weblate (Hebrew) Currently translated at 14.0% (283 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 105 +++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index ac4e963fd6..9fe06da9f1 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -170,7 +170,7 @@ כניסה צור חשבון שם משתמש - הצתרף אל חדר + הצטרף אל חדר קרא שלח פנימה התקדמות (%%%) @@ -191,4 +191,107 @@ אין קבוצות קהילות הזמנה + שם משתמש זה כבר בשימוש + יותר מדי בקשות נשלחו + לא מכיל JSON חוקי + JSON פגום + אסימון הגישה שצוין לא זוהה + שם משתמש / סיסמא שגויים + המכשיר שלך משתמש בפרוטוקול אבטחה TLS מיושן, הפגיע להתקפה, למען ביטחונך לא תוכל להתחבר + שגיאת SSL. + שגיאת SSL: זהות העמית לא אומתה. + לא ניתן להגיע לשרת בית בכתובת אתר זו, אנא בדוק זאת + זו אינה כתובת שרת מטריקס חוקית + לא ניתן להגיע לכתובת אתר זו, אנא בדוק אותה + אנא הכנס כתובת תקינה + לא ניתן להירשם: כשל בבעלות על דוא\"ל + לא ניתן להירשם + לא ניתן להירשם: שגיאת רשת + לא מצליח להתחבר + לא ניתן להתחבר: שגיאת רשת + כתובת האתר חייבת להתחיל ב- http [s]: // + אנא עיין וקבל את המדיניות של שרת בית זה: + הסיסמה שלך אופסה. +\n +\nהוצאת מכל ההפעלות ולא תקבל עוד התראות דחיפה. כדי להפעיל מחדש התראות, התחבר מחדש בכל מכשיר. + אימות כתובת הדוא\"ל נכשל: ודא שלחצת על הקישור בדוא\"ל + דוא\"ל נשלח אל% s. לאחר שתעקוב אחר הקישור שהוא מכיל, לחץ למטה. + יש להזין סיסמה חדשה. + יש להזין את כתובת הדוא\"ל המקושרת לחשבונך. + כדי לאפס את הסיסמה שלך, הזן את כתובת הדוא\"ל המקושרת לחשבונך: + אימתתי את כתובת הדוא\"ל שלי + שרת זיהוי: + שרת הבית + שם משתמש כבר נמצא בשימוש + שרת בית זה רוצה לוודא שאתה לא רובוט + הרשמה באמצעות דוא\"ל ומספר טלפון בבת אחת עדיין אינה נתמכת עד להתקנת ה- API. רק מספר הטלפון ייקח בחשבון. +\n +\nתוכל להוסיף את הדוא\"ל שלך לפרופיל שלך בהגדרות. + אנא בדוק את הדוא\"ל שלך כדי להמשיך בהרשמה + השתמש באפשרויות שרת מותאמות אישית (מתקדם) + שכחת סיסמה\? + סיסמא אינה תואמת לקודמתה + מטבע אינו חוקי + כתובת דוא\"ל או מספר טלפון חסרים + מספר טלפון חסר + כתובת דוא\"ל חסרה + מספר הטלפון הזה כבר קיים ומעודכן במערכת. + כתובת הדוא\"ל הזו כבר קיימת ומוגדרת במערכת. + זה אינו נראה כמספר טלפון חוקי + זה לא נראה כמו כתובת דוא\"ל חוקית + סיסמה חסרה + סיסמה קצרה מדי (נדרש לפחות 6 תווים) + שמות משתמשים עשויים להכיל רק אותיות, מספרים, נקודות, מקפים וקו תחתון + שם משתמש ו/או סיסמה לא נכונים + אשר את סיסמתך החדשה + חזור על הסיסמה + מספר טלפון (אופציונלי) + מספר טלפון + כתובת דוא\"ל (אופציונלי) + כתובת דוא\"ל + הגדר דוא\"ל לשחזור חשבון. השתמש באימייל או בטלפון מאוחרים יותר כדי שאפשר יהיה לגלות אותו על ידי אנשים שמכירים אותך. + הגדר דוא\"ל לשחזור חשבון. השתמש באימייל או בטלפון מאוחרים יותר כדי שאפשר יהיה לגלות אותו על ידי אנשים שמכירים אותך. + הגדר טלפון, ואחר כך יהיה ניתן לגלות אותו על ידי אנשים שמכירים אותך. + הגדר דוא\"ל לשחזור חשבון, ומאוחר יותר כך שניתן יהיה לגלות אותו על ידי אנשים שמכירים אותך. + שם משתמש + סיסמה חדשה + סיסמה + מייל או שם משתמש + חזור למסך כניסה + שלח מייל איפוס + דלג + הגש + צור חשבון + היכנס באמצעות כניסה יחידה + היכנס + מצטערים, לא נמצאה יישום חיצוני להשלמת פעולה זו. + המשך עם… + כרגע אין לך חבילות מדבקה מופעלות. +\n +\nלהוסיף כמה עכשיו\? + צלם סרטון + צלם תמונה + צלם תמונה או סרטון + שלח סטיקר + שלח קבצים + הפעל מצב HD + כבה מצב HD + אחורה + קדימה + החלף בין מצלמה + אוזניות אלחוטיות + אוזניות + רמקול + טלפון + בחר מכשיר סאונד + נכשל החיבור בזמן אמת. +\nאנא בקש ממנהל שרת הבית שלך להגדיר שרת TURN על מנת שהשיחות יעבדו בצורה אמינה. + שיחת האלמנט נכשלה + אל תשאל אותי שוב + נסה להשתמש ב-% s + אנא בקש ממנהל שרת הבית שלך (% 1 $ s) להגדיר שרת TURN כדי שהשיחות יעבדו בצורה אמינה. +\n +\nלחלופין, אתה יכול לנסות להשתמש בשרת הציבורי ב-% 2 $ s, אך זה לא יהיה אמין כל כך, והוא ישתף את כתובת ה- IP שלך עם השרת הזה. תוכל לנהל זאת גם בהגדרות. + השיחה נכשלה עקב שרת שהוגדר כהלכה + האם אתה בטוח שברצונך להתחיל שיחת וידאו\? \ No newline at end of file From 245d580825e90de523afde07528b095283813b73 Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Fri, 8 Jan 2021 13:49:54 +0000 Subject: [PATCH 166/224] Translated using Weblate (Hebrew) Currently translated at 14.0% (283 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 9fe06da9f1..31ed0815ec 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -294,4 +294,5 @@ \nלחלופין, אתה יכול לנסות להשתמש בשרת הציבורי ב-% 2 $ s, אך זה לא יהיה אמין כל כך, והוא ישתף את כתובת ה- IP שלך עם השרת הזה. תוכל לנהל זאת גם בהגדרות. השיחה נכשלה עקב שרת שהוגדר כהלכה האם אתה בטוח שברצונך להתחיל שיחת וידאו\? + האם אתה בטוח שברצונך להתחיל שיחה קולית\? \ No newline at end of file From d3a3ba80794386c1bf49c5e98c6c334e36f3a95d Mon Sep 17 00:00:00 2001 From: Ahrale Date: Fri, 8 Jan 2021 14:36:09 +0000 Subject: [PATCH 167/224] Translated using Weblate (Hebrew) Currently translated at 18.1% (367 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 31ed0815ec..5bfdafd59b 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -221,7 +221,7 @@ כדי לאפס את הסיסמה שלך, הזן את כתובת הדוא\"ל המקושרת לחשבונך: אימתתי את כתובת הדוא\"ל שלי שרת זיהוי: - שרת הבית + שרת הבית: שם משתמש כבר נמצא בשימוש שרת בית זה רוצה לוודא שאתה לא רובוט הרשמה באמצעות דוא\"ל ומספר טלפון בבת אחת עדיין אינה נתמכת עד להתקנת ה- API. רק מספר הטלפון ייקח בחשבון. From bc2f49fa31a84c7f2c3cea2d9f4cdbe0385d6e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Fri, 8 Jan 2021 14:02:15 +0000 Subject: [PATCH 168/224] Translated using Weblate (Hebrew) Currently translated at 18.1% (367 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 94 +++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 5bfdafd59b..3bef403741 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -295,4 +295,98 @@ השיחה נכשלה עקב שרת שהוגדר כהלכה האם אתה בטוח שברצונך להתחיל שיחת וידאו\? האם אתה בטוח שברצונך להתחיל שיחה קולית\? + צ\'ט חדש + הוסף שרת זהות בהגדרות שלך כדי לבצע פעולה זו. + זו תצוגה מקדימה של החדר הזה. אינטראקציות בחדר הושבתו. + חדר + אתה מנסה לגשת ל-% s. האם תרצה להצטרף על מנת להשתתף בדיון\? + הזמנה זו נשלחה אל% s, שאינה משויכת לחשבון זה. +\nייתכן שתרצה להתחבר עם חשבון אחר, או להוסיף דוא\"ל זה לחשבונך. + הוזמנת להצטרף לחדר זה על ידי% s + קפיצה להודעה הראשונה שלא נקראה. + מסנכרן… + פתח כותרת + חברי רשימה + דחייה + תצוגה מקדימה + הצטרף + הסר + המשך + לא!! + כן! + שמור להורדות\? + נשמר + אפשר הרשאה לגשת לאנשי הקשר שלך. + כדי לסרוק קוד QR, עליך לאפשר גישה למצלמה. + מצטער. הפעולה לא בוצעה בגלל הרשאות חסרות + אלמנט יכול לבדוק את פנקס הכתובות שלך כדי למצוא משתמשי מטריקס אחרים על סמך מספרי הדוא\"ל והטלפון שלהם. +\n +\nהאם אתה מסכים לשתף את פנקס הכתובות שלך למטרה זו\? + אלמנט יכול לבדוק את פנקס הכתובות שלך כדי למצוא משתמשי מטריקס אחרים על סמך מספרי הדוא\"ל והטלפון שלהם. אם אתה מסכים לשתף את פנקס הכתובות שלך למטרה זו, אנא הגש גישה בחלון הקופץ הבא. + אלמנט זקוק להרשאה כדי לגשת למצלמה ולמיקרופון שלך כדי לבצע שיחות וידאו. +\n +\nאנא אפשר גישה בחלונות הקופצים הבאים כדי להיות מסוגל לבצע את השיחה. + " +\n +\nאנא אפשר גישה בחלון הקופץ הבא כדי שתוכל לבצע את השיחה." + אלמנט זקוק להרשאה כדי לגשת למיקרופון שלך כדי לבצע שיחות שמע. + " +\n +\nאנא אפשר גישה בחלון הקופץ הבא כדי שתוכל לבצע את השיחה." + אלמנט זקוק להרשאה כדי לגשת למצלמה שלך כדי לצלם תמונות ושיחות וידאו. + אלמנט זקוק להרשאה כדי לגשת לספריית התמונות והווידיאו שלך כדי לשלוח ולשמור קבצים מצורפים. +\n +\nאנא אפשר גישה בחלון הקופץ הבא כדי שתוכל לשלוח קבצים מהטלפון שלך. + מידע + לא ניתן להקליט וידאו + צלם תמונה או סרטון + השיחה נענתה במקום אחר + לא ניתן לאתחל את המצלמה + חיבור המדיה נכשל + הצד המרוחק לא הצליח להרים. + חזור לשיחה + שיחה פעילה (% s) + שיחת וידאו מתבצעת … + במהלך התקשרות… + שיחה קולית נכנסת + שיחת וידאו נכנסת + שיחה נכנסת + מתקשר… + שיחה הסתיימה + שיחה מתחברת … + שיחה מחוברת + שִׂיחָה + בחר רינגטון לשיחות: + רינגטון שיחה נכנסת + ישתמש ב-% s כסיוע כאשר השרת הביתי שלך אינו מציע כזה (כתובת ה- IP שלך תשותף במהלך שיחה) + אפשר שרת עזרה לשיחות + השתמש ברינגטון ברירת המחדל של אלמנט לשיחות נכנסות + בקש אישור לפני שמתחילים בשיחה + מנע שיחה מקרית + שיחות + נושא החדר + שם חדר + היום + אתמול + %1$dm %2$ds + % d s + האם לבטל את ההעלאה\? + האם לבטל את ההורדה\? + קטן + בינוני + גדול + מקורי + שלח כ: + + שינוי בפרט חברות + שינוי בפרטי חברות + שינוי בפרטי חברות + שינוי בפרטי חברות + + רשימת קבוצות + קרא את רשימת הקבלות + הפעל את Element במכשיר אחר שיכול לפענח את ההודעה כדי שיוכל לשלוח את המפתחות להפעלה זו. + הבקשה נשלחה + בקשת המפתח נשלחה. + בקש מחדש מפתחות הצפנה מהפעלות האחרות שלך. \ No newline at end of file From 819f0c021eba6ef78dbebcaad9eb49b6276cb1c3 Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Fri, 8 Jan 2021 13:54:07 +0000 Subject: [PATCH 169/224] Translated using Weblate (Hebrew) Currently translated at 18.1% (367 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 3bef403741..11329fe384 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -389,4 +389,10 @@ הבקשה נשלחה בקשת המפתח נשלחה. בקש מחדש מפתחות הצפנה מהפעלות האחרות שלך. + בטל הכל + שלח מחדש הכל + הודעות לא נשלחו בגלל הימצאות פעילויות לא ידועות. %1$s או %2$s עכשיו\? + הודעות לא נשלחו. %1$s או %2$s עכשיו\? + הקישוריות לשרת אבדה. + שלח תשובה (לא מוצפן) … \ No newline at end of file From 54f6440bcfb264f485ddd5a8526408dc05f2db3f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 29 Dec 2020 10:44:37 +0100 Subject: [PATCH 170/224] super.onClear() called at the end --- .../verification/choose/VerificationChooseMethodViewModel.kt | 2 +- .../app/features/discovery/DiscoverySettingsViewModel.kt | 2 +- .../main/java/im/vector/app/features/login/LoginViewModel.kt | 3 +-- .../app/features/roomdirectory/RoomDirectoryViewModel.kt | 2 +- .../im/vector/app/features/signout/soft/SoftLogoutViewModel.kt | 3 +-- .../features/workers/signout/ServerBackupStatusViewModel.kt | 2 +- .../app/features/workers/signout/SignoutCheckViewModel.kt | 2 +- 7 files changed, 7 insertions(+), 9 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt index e309869479..4518a8d6b7 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt @@ -89,8 +89,8 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( } override fun onCleared() { - super.onCleared() session.cryptoService().verificationService().removeListener(this) + super.onCleared() } companion object : MvRxViewModelFactory { diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt index 0f294e080a..d16ebcdc8b 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt @@ -93,8 +93,8 @@ class DiscoverySettingsViewModel @AssistedInject constructor( } override fun onCleared() { - super.onCleared() stopListenToIdentityManager() + super.onCleared() } override fun handle(action: DiscoverySettingsAction) { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt index 666bd21add..a3f1c36d08 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt @@ -810,9 +810,8 @@ class LoginViewModel @AssistedInject constructor( } override fun onCleared() { - super.onCleared() - currentTask?.cancel() + super.onCleared() } fun getInitialHomeServerUrl(): String? { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt index c58e255bcc..b047b2ede9 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt @@ -221,7 +221,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: } override fun onCleared() { - super.onCleared() currentTask?.cancel() + super.onCleared() } } diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt index f1d9a66342..81ac1dbd54 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt @@ -232,8 +232,7 @@ class SoftLogoutViewModel @AssistedInject constructor( } override fun onCleared() { - super.onCleared() - currentTask?.cancel() + super.onCleared() } } diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt index 48f83b6c54..68f62cffe5 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt @@ -157,8 +157,8 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS } override fun onCleared() { - super.onCleared() session.cryptoService().keysBackupService().removeListener(this) + super.onCleared() } override fun onStateChange(newState: KeysBackupState) { diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt index 48426be723..8a1055e780 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt @@ -107,8 +107,8 @@ class SignoutCheckViewModel @AssistedInject constructor(@Assisted initialState: } override fun onCleared() { - super.onCleared() session.cryptoService().keysBackupService().removeListener(this) + super.onCleared() } override fun onStateChange(newState: KeysBackupState) { From e21c8792e61cff0b47db8c1d021a21d07d890b40 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 29 Dec 2020 12:20:24 +0100 Subject: [PATCH 171/224] Fix switch theme issue, and white field issue (#2599, #2528) Remove some workarounds. I cannot reproduce the bug of signout which does not destroy the HomeActivityViewModel... --- CHANGES.md | 2 ++ vector/src/main/AndroidManifest.xml | 3 +-- vector/src/main/java/im/vector/app/features/MainActivity.kt | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 8a69aea6fd..a474ef6711 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,8 @@ Bugfix 🐛: - Hiding membership events works the exact opposite (#2603) - Tapping drawer having more than 1 room in notifications gives "malformed link" error (#2605) - Initial sync is not retried correctly when there is some network error. (#2632) + - Fix switch theme issue, and white field issue (#2599, #2528) + Translations 🗣: - diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 4ad51fdea7..0341059674 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -82,8 +82,7 @@ + android:name=".features.home.HomeActivity" /> (), UnlockedActiv intent.putExtra(EXTRA_ARGS, args) activity.startActivity(intent) - // Ensure all the Activities are destroyed, it seems that the intent flags are not enough now. - activity.finishAffinity() } } From 8de4b0bb2059df506d9100f42eff57f878f78fe5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 29 Dec 2020 14:41:16 +0100 Subject: [PATCH 172/224] Small formatting --- .../internal/task/CoroutineSequencersTest.kt | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt index 667e0b2471..74b6c03d93 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt @@ -38,19 +38,16 @@ class CoroutineSequencersTest: MatrixTest { val jobs = listOf( GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#1") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#1") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#2") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#2") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#3") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#3") } + .also { results.add(it) } } ) runBlocking { @@ -70,19 +67,16 @@ class CoroutineSequencersTest: MatrixTest { val results = ArrayList() val jobs = listOf( GlobalScope.launch(dispatcher) { - sequencer1.post { suspendingMethod("#1") }.also { - results.add(it) - } + sequencer1.post { suspendingMethod("#1") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer2.post { suspendingMethod("#2") }.also { - results.add(it) - } + sequencer2.post { suspendingMethod("#2") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer3.post { suspendingMethod("#3") }.also { - results.add(it) - } + sequencer3.post { suspendingMethod("#3") } + .also { results.add(it) } } ) runBlocking { @@ -97,20 +91,17 @@ class CoroutineSequencersTest: MatrixTest { val results = ArrayList() val jobs = listOf( GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#1") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#1") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - val result = sequencer.post { suspendingMethod("#2") }.also { - results.add(it) - } - println("Result: $result") + sequencer.post { suspendingMethod("#2") } + .also { results.add(it) } + .also { println("Result: $it") } }, GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#3") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#3") } + .also { results.add(it) } } ) // We are canceling the second job From 76f4a1b4f1f52037b98261200dfab1083be43fde Mon Sep 17 00:00:00 2001 From: Andreas Kelemen Date: Fri, 8 Jan 2021 20:31:00 +0000 Subject: [PATCH 173/224] Translated using Weblate (Greek) Currently translated at 21.7% (439 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 44 +++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 5b3f3aaafc..f8ffb8c35b 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -333,4 +333,48 @@ Κανένα Παραμείνατε H δημιουργία αντιγράφων κλειδιού ασφαλείας θα πρέπει να είναι ενεργή σε όλες τις συνεδρίες σας για να αποφύγετε την απώλεια πρόσβασης στα κρυπτογραφημένα μηνύματά σας. + Επαναφόρτωση γραφικού στοιχείου + Αποτυχία φόρτωσης γραφικού στοιχείου +\n%s + Η χρήση του ενδέχεται να δημιουγίσει cookies και να κοινοποιήσει δεδομένα με %s: + Η χρήση του ενδέχεται να κοινοποιεί δεδομένα με %s: + Αυτο το γραφικό στοιχείο προστέθηκε από: + Φόρτωση Γραφικού στοιχείου + Γραφικό στοιχείο + Ενεργά γραφικά στοιχεία + Προβολή + Είστε βέβαιοι ότι θέλετε να διαγράψετε το γραφικό στοιχείο από αυτό το δωμάτιο; + Δημιουργήστε κλήσεις συνδιάσκεψης με το jitsi + Η δημιουργία γραφικού στοιχείου απέτυχε + Χρειάζεστε άδεια για να τροποποιήσετε τα γραφικά στοιχεία (widgets) σε αυτό το δωμάτιο + Εξαιρετικά Μεγάλο + Μεγαλύτερο + Αναζήτηση ιστορικού + %1$s: %2$s %3$s + %1$s: %2$s + ** Αποτυχία αποστολής - Παρακαλώ ανοίξτε το δωμάτιο + Εγώ + Καυνούργια Πρόσκληση + Καινούργια Μηνύματα + Δωμάτιο + Καινούργιο Συμβάν + %1$s και %2$s + %1$s στο %2$s και %3$s + + %d ειδοποιήση + %d ειδοποιήσεις + + + %1$s: %2$d μήνυμα + %1$s: %2$d μηνύματα + + + %d πρόσκληση + %d προσκλήσεις + + + 1 μη αναγνωσμένη ειδοποίηση + %d μη αναγνωσμένες ειδοποιήσεις + + Σύνδεση \ No newline at end of file From 0c77f49ffd86ec5cdcd04f72e3e9849386ef4a8e Mon Sep 17 00:00:00 2001 From: Constantinos Miltiadis Date: Fri, 8 Jan 2021 20:22:48 +0000 Subject: [PATCH 174/224] Translated using Weblate (Greek) Currently translated at 21.7% (439 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index f8ffb8c35b..07282dd6e4 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -377,4 +377,30 @@ %d μη αναγνωσμένες ειδοποιήσεις Σύνδεση + Λόγος οριστικής αποβολής + Οριστική αποβολή χρήστη + Αποβάλλοντας αυτό το χρήση θα τους αφαιρέσαι από το δωμάτιο. +\nΓια να τους + Λόγος αποβολής + Αποβολή χρήστη + Είστε σίγουροι πως θέλετε να καταργήσετε την πρόσκληση προς αυτό τον χρήστη; + Ακύρωση πρόσκλησης + Κατάργηση παράβλεψης + Καταργώντας την παράβλεψη αυτού του χρήστη θα επανφανίσει όλα τα μηνύματα από αυτούς + Παράβλεψη χρήστη + Παραβλέποντας αυτό το χρήση θα αφαιρέσει τα μηνύματα τους από δωμάτια που μοιράζεστε. +\nΜπορείτε να αντιστρέψετε αυτή την ενέργεια οποτεδήποτε στις γενικές ρυθμίσεις. + Παράβλεψη + Κατάργηση παράβλεψης χρήστη + Υποβίβαση + Αυτή δεν είναι έγκυρη διεύθυνση διακομιστή Matrix + Aυτή η διεύθυνση δεν είναι προσβάσιμη, παρακαλώ ελέγξτε + Παρακαλω εισάξετε έγκυρη διεύθυνση + Όνομα χρήστη + Νέος κωδικός + Κωδικός + Ηλεκτρονική διεύθυνση ή όνομα χρήστη + Επιστροφή στην οθόνη σύνδεσης + Υποβολή + Δημιουργία Λογαριασμού \ No newline at end of file From b6dda73cb1ebdc88e07e30bda0d5779508fe26bf Mon Sep 17 00:00:00 2001 From: Petros Koutsolampros Date: Fri, 8 Jan 2021 20:07:01 +0000 Subject: [PATCH 175/224] Translated using Weblate (Greek) Currently translated at 21.7% (439 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 94 ++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 07282dd6e4..76eeb27d24 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -96,7 +96,7 @@ Δεν υπάρχουν δωμάτια Δεν υπάρχουν δημόσια δωμάτια - 1 χρήστης + %d χρήστης %d χρήστες Πρόσκληση @@ -403,4 +403,96 @@ Επιστροφή στην οθόνη σύνδεσης Υποβολή Δημιουργία Λογαριασμού + Αυτό το δωμάτιο δεν έχει τοπικές διευθύνσεις + Να μην αποστέλλονται κρυπτογραφημένα μηνύματα σε μή επαληθευμένες περιόδους σύνδεσης σε αυτό το δωμάτιο από αυτή την περίοδο σύνδεσης. + Κρυπτογράφηση μόνο επαληθευμένων περιόδους σύνδεσης + Πρέπει να αποσυνδεθείτε για να μπορέσετε να ενεργοποιήσετε την κρυπτογράφηση. + Ενεργή κρυπτογράφηση από άκρο σε άκρο + Κρυπτογράφηση από άκρο σε άκρο + Αυτά είναι πειραματικά χαρακτηριστικά τα οποία μπορούν να παρουσιάσουν μη αναμενόμενα σφάλματα. Χρησιμοποιήστε με προσοχή. + Εργαστήρια + Εσωτερικός κωδικός δωματίου + + %d απαγορευμένος χρήστης + %d απαγορευμένοι χρήστες + + Απαγορευμένοι χρήστες + Όποιος γνωρίζει τη διεύθυνση δωματίου, συμπεριλαμβανομένων των επισκεπτών + Όποιος γνωρίζει τη διέθυνση δωματίου, εκτός από επισκέπτες + Μόνο όσοι έχουν προσκληθεί + Για να δημιουργήσετε σύνδεση σε ένα δωμάτιο, πρέπει να έχει διεύθυνση. + Μέλη μόνο (από τη στιγμή που μπήκαν) + Μέλη μόνο (από τη στιγμή που καλέστηκαν) + Μέλη μόνο (από τη στιγμή επιλογής αυτής της ρύθμισης) + Δημοσίευση αυτού του δωματίου στο κοινό κατάλογο δωματίων του %1$s; + Δεν είναι δυνατή η ανάκτηση της τρέχουσας ορατότητας καταλόγου δωματίων (%1$s). + Κατάργηση δημοσίευσης αυτής της διεύθυνσης + Δεν βρέθηκαν εξωτερικές εφαρμογές για αυτή την πράξη. + συνεχίστε με… + Δεν έχετε ενεργοποιημένα πακέτα αυτοκόλλητων. +\n +\nΘέλετε να προσθέσετε μερικά τώρα; + Φωτογραφία ή βίντεο + Βίντεο + Φωτογραφία + Αποστολή αυτοκόλλητου + Ενεργοποίηση Υψηλής Ανάλυσης + Απενεργοποίηση Υψηλής Ανάλυσης + Πίσω + Μπροστινή + Αλλαγή Κάμερας + Ασύρματο Ακουστικό + Ακουστικό + Ομιλητής + Τηλέφωνο + Αλλαγή Συσκευής Ήχου + Αποτυχία σύνδεσης σε πραγματικό χρόνο. +\nΖητήστε από τον διαχειριστή του οικιακού σας διακομιστή να διαμορφώσει έναν διακομιστή TURN ώστε οι κλήσεις να λειτουργούν αξιόπιστα. + Η Κλήση Element Aπέτυχε + Να μην ερωτηθώ ξανά + Προσπαθήστε να χρησιμοποιήσετε το %s + Παρακαλώ ζητήστε απο τον διαχειριστή του ιδιέταιρου διακομιστή (%1$s) να ρυθμίσει ένα διακομιστή TURN ώστε οι κλήσεις να δουλέυουν αξιόπιστα. +\n +\nΑλλιώς, μπορείτε να δοκιμάσετε τον δημόσιο διακομιστή στο %2$s, αλλά αυτό δεν θα είναι τόσο αξιόπιστο, και η IP διέυθυνσή σας θα σταλεί σε αυτό το διακομιστή. Μπορείτε να διαχειριστείτε τη διαδικασία στις Ρυθμίσεις. + Η κλήση απέτυχε λόγω λανθασμένα ρυθμισμένου διακομιστή + Είσαστε σίγουροι ότι θέλετε να κάνετε κλήση βίντεο; + Είσαστε σίγουροι ότι θέλετε να κάνετε κλήση ήχου; + Είσαστε σίγουροι οτι θέλετε να ξεκινήσετε μια νέα συζήτηση με τον/την %s; + Αποστολή φωνής + Κλήση βίντεο + Κλήση ήχου + Νέα συζήτηση + Διέυθυνση URL Ιδιαίτερου Διακομιστή + Διεύθυνση URL Διακομιστή Ταυτότητας + Είσοδος στο δωμάτιο + Αποστολή εντός + Η εφαργμογή διακόπηκε απότομα προηγουμένως. Θα θέλατε να ανοίξετε την οθόνη αναφοράς σφάλματος; + Αποστολή στιγμιότυπου οθόνης + Αποστολή ιστορικού αιτήσεων αποστολής κλειδιού + Δεν τέθηκε διακομιστής ταυτότητας. + Δεν υπάρχουν άλλα αποτελέσματα + Βιβλίο διευθύνσεων + Επιτυχία + Κατάργηση δημοσίευσης + Αντιγραφή + Ιστορικά + Τέλος κλήσης + Τρέχουσα κλήση συνδιάσκεψης. +\nΣυνδεθείτε με %1$s ή %2$s + Δεν επιτρέψατε στο Element την πρόσβαση στις επαφές σας + Ειδοποιήσεις + Αντιγράφηκε στο πρόχειρο + Πρόσθεση + Σημείωσε ως διαβασμένο + Είσαστε σίγουροι ότι θέλετε να αποσυνδεθείτε; + Ξεκινήστε συζήτηση + Παρακαλώ εισάγετε όνομα χρήστη. + Παρακαλώ ξεχάστε όλα τα μηνύματα τα οποία έχω στείλει μόλις απενεργοποιηθεί ο λογαριασμός μου (Προειδοποίηση: αυτό σημαίνει οτι μελλοντικοί χρήστες θα έχουν μία ατελή εικόνα των συζητήσεων) + Αυτό θα κάνει το λογαριασμό σας μόνιμα άχρηστο. Δε θα μπορέσετε να συνδεθείτε ξανα, και κανείς δεν θα μπορεί να εγγραφεί με το ίδιο όνομα χρήστη. Ο λογαριασμός σας θα αναχωρήσει από όλα τα δωμάτια στα οποία συμμετέχει, και οι πληροφορίες λογαριασμού θα αφαιρεθούν από το διακομιστή ταυτότητας. Αυτή η πράξη είναι μη αναστρέψιμη. +\n +\nΜε την απενεργοποίηση του λογαρισμού σας δεν θα ξεχαστούν τα μηνύματά που έχετε στείλει. Εάν θα θέλατε να ξεχαστούν, τότε δηλώστε το στο κουτί πιο κάτω. +\n +\nΗ ορατότητα μηνυμάτων δουλεύει σαν το ηλεκτρονικό ταχυδρομείο. Το να ξεχαστούν τα μηνύματα σημαίνει οτι μηνύματα τα οποία έχετε στείλει δεν θα σταλούν σε νέους ή μη-εγγεγραμμένους χρήστες, αλλα εγγεγραμμένοι χρήστες οι οποίοι έχουν ήδη πρόσβαση σε αυτά τα μηνύματα θα μπορούν ακόμα να τα δούν. + Λησμόνηση δωματίου + Αυτό το δωμάτιο έχει αντικατασταθεί και δεν είναι πια ενεργό \ No newline at end of file From 61be2dd3df3d45522405d51def8a076ecf2eff47 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 8 Jan 2021 16:30:59 +0000 Subject: [PATCH 176/224] Translated using Weblate (Greek) Currently translated at 21.7% (439 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 76eeb27d24..d11f676466 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -495,4 +495,5 @@ \nΗ ορατότητα μηνυμάτων δουλεύει σαν το ηλεκτρονικό ταχυδρομείο. Το να ξεχαστούν τα μηνύματα σημαίνει οτι μηνύματα τα οποία έχετε στείλει δεν θα σταλούν σε νέους ή μη-εγγεγραμμένους χρήστες, αλλα εγγεγραμμένοι χρήστες οι οποίοι έχουν ήδη πρόσβαση σε αυτά τα μηνύματα θα μπορούν ακόμα να τα δούν. Λησμόνηση δωματίου Αυτό το δωμάτιο έχει αντικατασταθεί και δεν είναι πια ενεργό + Μιλήστε \ No newline at end of file From d649cb4aa50f87466c600eb818d28df45a5d393f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Fri, 8 Jan 2021 12:56:48 +0000 Subject: [PATCH 177/224] Translated using Weblate (Ukrainian) Currently translated at 60.5% (1222 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/uk/ --- vector/src/main/res/values-uk/strings.xml | 310 ++++++++++++++++++++++ 1 file changed, 310 insertions(+) diff --git a/vector/src/main/res/values-uk/strings.xml b/vector/src/main/res/values-uk/strings.xml index 2ea129164a..b4ad0d4bd9 100644 --- a/vector/src/main/res/values-uk/strings.xml +++ b/vector/src/main/res/values-uk/strings.xml @@ -1155,4 +1155,314 @@ \n \nЗупинити змінювання пароля\? Ви успішно змінили налаштування кімнати + Тепер ваші ключі шифрування резервно копіюються у фоновому режимі на домашній сервер. Початкове резервне копіювання може зайняти кілька хвилин. + Резервне копіювання розпочато + Неочікувана помилка + Ключ відновлення + Створення ключа відновлення за допомогою парольної фрази, цей процес може зайняти кілька секунд. + Поділитися ключем відновлення з… + Будь ласка, зробіть копію + Стій + Замінити + Схоже, у вас вже є резервне копіювання ключа налаштування з іншого сеансу. Ви хочете замінити його тим, який ви створюєте\? + Резервна копія вже існує на вашому HomeServer + Ключ відновлення збережено. + Ключ відновлення збережено у папці \"% s\". +\n +\nПопередження: цей файл може бути видалено, якщо програму видалено. + Зберегти як файл + Поділіться + Збережіть ключ відновлення + Я зробив копію + Готово + Тримайте ключ відновлення десь дуже надійно, наприклад, менеджер паролів (або сейф) + Ваш ключ відновлення - це мережа безпеки - ви можете використовувати його для відновлення доступу до ваших зашифрованих повідомлень, якщо ви забудете свою парольну фразу. +\nТримайте ключ відновлення десь дуже надійно, наприклад, менеджер паролів (або сейф) + Ваші ключі резервно копіюються. + Успіху! + (Додатково) Налаштування за допомогою ключа відновлення + Або захистіть свою резервну копію за допомогою ключа відновлення, зберігаючи її десь у безпеці. + Створення резервної копії + Встановіть парольну фразу + Ми збережемо зашифровану копію ваших ключів на вашому домашньому сервері. Захистіть свою резервну копію парольною фразою, щоб захистити її. +\n +\nДля максимальної безпеки він повинен відрізнятися від пароля вашого облікового запису. + Захистіть свою резервну копію за допомогою парольної фрази. + Експорт ключів вручну + Почніть використовувати резервне копіювання ключів + Повідомлення в зашифрованих кімнатах захищаються наскрізним шифруванням. Тільки ви та одержувач (и) маєте ключі для читання цих повідомлень. +\n +\nНадійно створіть резервну копію клавіш, щоб не втратити їх. + Ніколи не втрачайте зашифровані повідомлення + Немає сесії Matrix + Видаліть парольну фразу, якщо хочете, щоб Element створив ключ відновлення. + Парольна фраза занадто слабка + Введіть парольну фразу + Не знайдено дійсного файлу .apk сервісів Google Play. Сповіщення можуть працювати неправильно. + Введіть ім’я користувача. + Безмовний + Ігнорувати + Запит на розподіл ключів + Поділіться + Перевірити + Неперевірений сеанс запитує ключі шифрування. +\nНазва сесії:% 1 $ s +\nВостаннє бачено:% 2 $ s +\nЯкщо ви не ввійшли в інший сеанс, проігноруйте цей запит. + Нова сесія вимагає ключів шифрування. +\nНазва сесії:% 1 $ s +\nВостаннє бачено:% 2 $ s +\nЯкщо ви не ввійшли в інший сеанс, проігноруйте цей запит. + Для продовження потрібно прийняти Умови цієї послуги. + Немає активних віджетів + Керуйте інтеграціями + Менеджер інтеграції не налаштовано. + Прочитайте захищені DRM засоби масової інформації + Використовуйте мікрофон + Використовуйте камеру + Заблокувати все + Дозвольте + Цей віджет хоче використовувати такі ресурси: + На жаль, конференц-дзвінки з Jitsi не підтримуються на старих пристроях (пристрої з ОС Android нижче 5.0) + Ідентифікатор кімнати + Ідентифікатор віджета + Ваша тема + Ваш ідентифікатор користувача + URL-адреса вашого аватара + Ваше відображуване ім\'я + Скасувати доступ для мене + Відкрити в браузері + Перезавантажте віджет + Не вдалося завантажити віджет. +\n% s + Його використання може обмінюватися даними з% s: + За його допомогою можна встановити файли cookie та обмінюватися даними з% s: + Цей віджет додав: + Завантажити віджет + Віджет + Активні віджети + ПЕРЕГЛЯН + % 1 $ s:% 2 $ s% 3 $ s + % 1 $ s:% 2 $ s + ** Не вдалося надіслати - відкрийте кімнату + Я + Нове запрошення + Нові повідомлення + Кімната + Нова подія + % 1 $ s та% 2 $ s + % 1 $ s у% 2 $ s та% 3 $ s + + повідомлення + повідомлення + повідомлення + повідомлення + + + повідомлення + повідомлення + повідомлення + повідомлення + + + запрошення + запрошення + запрошення + запрошення + + невідомий ip + + Ключ% 1 $ d /% 2 $ d імпортовано з успіхом. + ключі, імпортовані з успіхом. + ключі, імпортовані з успіхом. + ключі, імпортовані з успіхом. + + Керування резервною копією ключів + Відновлення зашифрованих повідомлень + Ключі успішно експортовані + Публічну назву сеансу бачать люди, з якими ви спілкуєтесь + Публічне ім’я (видиме людям, з якими спілкуєтесь) + + % d заборонений користувач + % d заборонених користувачів + % d заборонених користувачів + % d заборонених користувачів + + Не вдається отримати поточну видимість каталогу кімнат (% 1 $ s). + Опублікувати цю кімнату для всіх у каталозі кімнат% 1 $ s\? + Скасувати публікацію цієї адреси + Опублікуйте цю адресу + Додайте місцеву адресу + У цій кімнаті немає місцевих адрес + Встановіть адреси для цієї кімнати, щоб користувачі могли знаходити цю кімнату через ваш домашній сервер (% 1 $ s) + Місцеві адреси + Нова опублікована адреса (наприклад, #alias: server) + Інших опублікованих адрес поки що немає. + Інших опублікованих адрес поки що немає, додайте одну нижче. + Опублікувати цю кімнату для всіх у каталозі кімнат% 1 $ s\? + Видалити адресу \"% 1 $ s\"\? + Скасувати публікацію адреси \"% 1 $ s\"\? + Опублікувати + Опублікуйте нову адресу вручну + Інші опубліковані адреси: + Основна адреса + Це основна адреса + Опубліковані адреси може використовувати будь-хто на будь-якому сервері для приєднання до вашої кімнати. Щоб опублікувати адресу, її потрібно спочатку встановити як локальну адресу. + Опубліковані адреси + Адреси кімнат + Перегляньте адреси цієї кімнати та керовані ними, а також їх видимість у каталозі кімнати. + Адреси номерів + Доступ до номера + Зміни щодо того, хто може читати історію, стосуватимуться лише майбутніх повідомлень у цій кімнаті. Видимість існуючої історії залишиться незмінною. + Відтворити звук затвора + Вибирайте + Медіа-джерело за замовчуванням + Вибирайте + Стиснення за замовчуванням + ЗМІ + Додаткова інформація:% s + Під час підтвердження номера телефону сталася помилка. + Паролі не збігаються + Пароль не дійсний + Оновити пароль + Під час підтвердження вашої адреси електронної пошти сталася помилка. + Увімкніть для цього параметр \"Дозволити інтеграцію\" у налаштуваннях. + Інтеграція вимкнена + Менеджер інтеграції + Дозволити інтеграції + Режим збереження даних застосовує певний фільтр, тому оновлення присутності та сповіщення про введення фільтруються. + Дайте дозвіл + Для отримання надійних сповіщень елементу потрібно підтримувати з’єднання у фоновому режимі з незначним ударом. +\nНа наступному екрані вам буде запропоновано дозволити Element завжди працювати у фоновому режимі, прийміть. + Фонове з’єднання + Це замінить ваш поточний ключ або фразу. + Створіть новий ключ безпеки або встановіть нову фразу безпеки для існуючої резервної копії. + Захистіть від втрати доступу до зашифрованих повідомлень та даних, створивши резервну копію ключів шифрування на своєму сервері. + Налаштуйте на цьому пристрої + Скиньте безпечне резервне копіювання + Налаштуйте безпечне резервне копіювання + Управління + Безпечне резервне копіювання + Включає події запрошення / приєднання / зліва / удару / заборони та зміни аватара / відображуваного імені. + Показати події держав-членів + Управління ключами криптографії + Використовуйте Integration Manager для керування ботами, мостами, віджетами та пакетами наклейок. +\nМенеджери інтеграції отримують дані конфігурації та можуть змінювати віджети, надсилати запрошення до кімнати та встановлювати рівні потужності від вашого імені. + Інтеграції + + % d секунди + % d секунди + % d секунди + % d секунди + + % s +\nСинхронізація може бути відкладена залежно від ресурсів (акумулятор) або стану пристрою (сплячий режим). + Бажаний інтервал синхронізації + Не вдалося оновити налаштування. + Ви не отримуватимете сповіщення про вхідні повідомлення, коли програма перебуває у фоновому режимі. + Немає фонової синхронізації + Елемент періодично синхронізуватиметься у фоновому режимі в певний час (налаштовується). +\nЦе вплине на використання радіо та акумулятора, з’явиться постійне сповіщення про те, що Element прослуховує події. + Оптимізовано для реального часу + Елемент синхронізується у фоновому режимі таким чином, щоб зберегти обмежені ресурси пристрою (акумулятор). +\nЗалежно від стану ресурсу вашого пристрою, синхронізація може бути відкладена операційною системою. + Оптимізовано для батареї + Режим фонової синхронізації + Додатки не потребують підключення до HomeServer у фоновому режимі, це має зменшити споживання батареї + Ігнорувати оптимізацію + Якщо користувач залишає пристрій відключеним та нерухомим протягом певного періоду часу, при вимкненому екрані, пристрій переходить у режим дрімання. Це запобігає доступу програм до мережі та відкладає їх завдання, синхронізацію та стандартні сигнали тривоги. + Оптимізація акумулятора не впливає на елемент. + Оптимізація акумулятора + Вимкнути обмеження + Фонові обмеження ввімкнено для елемента. +\nРобота, яку намагається виконати програма, буде агресивно обмежена, поки вона перебуває у фоновому режимі, і це може вплинути на сповіщення. +\n% 1 $ s + Фонові обмеження для елемента вимкнено. Цей тест слід проводити з використанням мобільних даних (без Wi-Fi). +\n% 1 $ s + Перевірте фонові обмеження + Увімкніть Пуск під час завантаження + Послуга не запуститься при перезавантаженні пристрою, ви не будете отримувати сповіщення, доки Element не буде відкрито один раз. + Сервіс почнеться після перезапуску пристрою. + Почніть із завантаження + Помилка перезапуску служби + Сервіс був убитий і перезапущений автоматично. + Автоматичний перезапуск служби сповіщень + Запустіть службу + Служба сповіщень не працює. +\nСпробуйте перезапустити програму. + Служба сповіщень працює. + Служба сповіщень + Повідомлення натиснуто! + Клацніть на сповіщення. Якщо ви не бачите сповіщення, перевірте налаштування системи. + Відображення сповіщень + Ви переглядаєте сповіщення! Клацніть на мене! + Не вдалося отримати push. Рішенням може бути перевстановлення програми. + Додаток отримує PUSH + Додаток чекає PUSH + Тестовий поштовх + Не вдалося зареєструвати маркер FCM на HomeServer: +\n% 1 $ s + Токен FCM успішно зареєстрований на HomeServer. + Реєстрація токена + Додати обліковий запис + [% 1 $ s] +\nЦя помилка вийшла з-під контролю Element. На телефоні немає облікового запису Google. Відкрийте менеджер облікових записів і додайте обліковий запис Google. + [% 1 $ s] +\nЦя помилка вийшла з-під контролю Element. Це може статися з кількох причин. Можливо, це спрацює, якщо ви спробуєте пізніше, ви також можете перевірити, чи не обмежена служба Google Play щодо використання даних у налаштуваннях системи, чи правильний годинник вашого пристрою, або це може статися на користувацькому ПЗУ. + [% 1 $ s] +\nЦя помилка вийшла з-під контролю Element, і за даними Google, ця помилка вказує на те, що на пристрої зареєстровано забагато програм у FCM. Помилка виникає лише у випадках, коли додатків надзвичайно багато, тому вона не повинна впливати на звичайного користувача. + Не вдалося отримати маркер FCM: +\n% 1 $ s + Успішно отримано маркер FCM: +\n% 1 $ s + Токен Firebase + Виправити послуги Play + Element використовує сервіси Google Play для доставки push-повідомлень, але, схоже, він налаштований неправильно: +\n% 1 $ s + Відкрийте Налаштування + Сповіщення вимкнено в налаштуваннях системи. +\nБудь ласка, перевірте налаштування системи. + Один або кілька тестів не пройшли, надішліть звіт про помилку, щоб допомогти нам розслідувати. + Одне або кілька тестів не вдалося, спробуйте запропоновані виправлення. + Основна діагностика в порядку. Якщо ви все ще не отримуєте сповіщення, надішліть звіт про помилку, щоб допомогти нам розслідувати. + Важливість повідомлення за подією + Переконайтеся, що ви натиснули посилання в електронному листі, який ми надіслали вам. + Видалити% s\? + Потрібна автентифікація + Це неможливо зробити за допомогою Element mobile + Підтвердити пароль + Фільтрувати заборонених користувачів + Скасування заборони користувачеві дозволить їм знову приєднатися до кімнати. + Розблокувати користувача + Причина заборони + Заборонити користувача + нога користувач видалить їх з цієї кімнати. +\n +\nЩоб запобігти їх повторному приєднанню, замість цього слід заборонити їх. + Причина для удару + Удар користувача + Дійсно скасувати запрошення для цього користувача\? + Скасувати запрошення + Ігнорування цього користувача знову покаже всі повідомлення від нього. + Ігнорувати користувача + Ігноруючи цього користувача, його повідомлення буде видалено з кімнат, якими ви ділитесь. +\n +\nВи можете будь-коли змінити цю дію в загальних налаштуваннях. + Ігнорувати користувача + Знизити + Ви не зможете скасувати цю зміну, оскільки знижуєтеся, якщо ви останній привілейований користувач у кімнаті, неможливо буде повернути собі привілеї. + Понизитися\? + Додайте сервер ідентифікації у свої налаштування, щоб виконати цю дію. + Дозвольте доступ до ваших контактів. + Щоб відсканувати QR-код, потрібно дозволити доступ до камери. + Повернутися до дзвінка + Триває відеодзвінок… + Використовуватиме% s як допоміжний, коли ваш домашній сервер не пропонує такого (ваша IP-адреса буде надана під час дзвінка) + Дозволити сервер допоміжних викликів + Ваш пристрій використовує застарілий протокол безпеки TLS, вразливий до атак, для вашої безпеки ви не зможете підключитися + Помилка SSL: особа однолітка не підтверджена. + Встановіть електронну адресу для відновлення облікового запису. Використовуйте пізніше електронну пошту або телефон, щоб люди, які вас знають, могли їх відкрити. + Встановіть електронну адресу для відновлення облікового запису. Використовуйте пізніше електронну пошту або телефон, щоб люди, які вас знають, могли їх відкрити. + Встановіть телефон, а пізніше, щоб його могли побачити люди, які вас знають. + Встановіть електронну адресу для відновлення облікового запису, а пізніше, щоб вона була необов’язковою для пошуку людьми, які вас знають. \ No newline at end of file From 08b38cd6ad369034d10d8ba82647a7394f2a0282 Mon Sep 17 00:00:00 2001 From: Andreas Kelemen Date: Fri, 8 Jan 2021 21:07:26 +0000 Subject: [PATCH 178/224] Translated using Weblate (Greek) Currently translated at 22.8% (462 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index d11f676466..2ac61c1e8f 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -32,7 +32,7 @@ Εντάξει Προειδοποίηση Συνέχεια - Γίνεται συγχρονισμός + Γίνεται συγχρονισμός… Ηχητικές ειδοποιήσεις Αθόρυβες ειδοποιήσεις Μηνύματα @@ -379,16 +379,18 @@ Σύνδεση Λόγος οριστικής αποβολής Οριστική αποβολή χρήστη - Αποβάλλοντας αυτό το χρήση θα τους αφαιρέσαι από το δωμάτιο. -\nΓια να τους + Αποβάλλοντας αυτό το χρήση θα τους αφαιρέσαι από το δωμάτιο. +\n +\nΕάν θέλετε να τους αποτρέψετε να συμμετάσχουν ξανά, θα πρέπει να τους αποβάλλετε οριστικά. Λόγος αποβολής Αποβολή χρήστη Είστε σίγουροι πως θέλετε να καταργήσετε την πρόσκληση προς αυτό τον χρήστη; Ακύρωση πρόσκλησης Κατάργηση παράβλεψης - Καταργώντας την παράβλεψη αυτού του χρήστη θα επανφανίσει όλα τα μηνύματα από αυτούς + Καταργώντας την παράβλεψη αυτού του χρήστη θα επανφανίσει όλα τα μηνύματα από αυτούς. Παράβλεψη χρήστη - Παραβλέποντας αυτό το χρήση θα αφαιρέσει τα μηνύματα τους από δωμάτια που μοιράζεστε. + Παραβλέποντας αυτό το χρήση θα αφαιρέσει τα μηνύματα τους από δωμάτια που μοιράζεστε. +\n \nΜπορείτε να αντιστρέψετε αυτή την ενέργεια οποτεδήποτε στις γενικές ρυθμίσεις. Παράβλεψη Κατάργηση παράβλεψης χρήστη From 996fe71de926375d4cdb31767eb6c0f7656fd568 Mon Sep 17 00:00:00 2001 From: Constantinos Miltiadis Date: Fri, 8 Jan 2021 21:07:19 +0000 Subject: [PATCH 179/224] Translated using Weblate (Greek) Currently translated at 22.8% (462 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 2ac61c1e8f..c9dfc29bd2 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -498,4 +498,29 @@ Λησμόνηση δωματίου Αυτό το δωμάτιο έχει αντικατασταθεί και δεν είναι πια ενεργό Μιλήστε + Παράβλεψη + Αποσύνδεση + Δεν εμπιστεύομαι + Δεν έχετε εξουσιοδότηση να δημοσιεύσετε σε αυτό το δωμάτιο + Το αρχείο δεν βρέθηκε + Διαγραφή μηνυμάτων που δεν στάληκαν + Επαναποστολή μηνυμάτων που δεν στάληκαν + Ακύρωση όλων + Επαναποστολή όλων + Απώλεια σύνδεσης με το διακομιστή. + Αποστολή απάντησης (κρυπτογραφημένη)… + Αποστολή κρυπτογραφημένης απάντησης… + Αποστολή μηνύματος (κρυπτογραφημένο)… + Αποστολή κρυπτογραφημένου μηνύματος… + %1$s & %2$s & άλλοι γράφουν… + % γράφει… + %1$s & %2$s γράφουν… + Συνομιλία + Διεύθυνση ηλεκτρονικού ταχυδρομίου ή Matrix ID + Πρόσκληση μέσω ID χρήστη + Μόνο χρήστες Matrix + Ευρετήριο χρηστών + Η μεταβλητή μπορεί να είναι ένα μόνο όνομα ή μια σειρά από ονόματα +\n(\"Aliki,\" + Λόγος \ No newline at end of file From 6bcd96d629b8631a980035dd33c5a314d0df5239 Mon Sep 17 00:00:00 2001 From: Constantinos Miltiadis Date: Fri, 8 Jan 2021 21:19:55 +0000 Subject: [PATCH 180/224] Translated using Weblate (Greek) Currently translated at 23.1% (468 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index c9dfc29bd2..27bfecc57a 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -523,4 +523,10 @@ Η μεταβλητή μπορεί να είναι ένα μόνο όνομα ή μια σειρά από ονόματα \n(\"Aliki,\" Λόγος + Δεν εξακριβώθηκε η ταυτότητα του εξωτερικού διακομιστή. + Απόκρυψη όλων των μηνυμάτων από αυτό το χρήστη; +\nΑυτή η ενέργεια θα επανεκκινήσει την εφαρμογή και ίσως πάρει λίγο χρόνο. + Λόγοι αναφοράς αυτού του περιεχομένου + Ρυθμίσεις + Λεπτομέρειες Δωματίου \ No newline at end of file From 54e501127c88bdc0259fb5f4f057fab960e58661 Mon Sep 17 00:00:00 2001 From: Andreas Kelemen Date: Fri, 8 Jan 2021 21:08:40 +0000 Subject: [PATCH 181/224] Translated using Weblate (Greek) Currently translated at 23.1% (468 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 27bfecc57a..8400b32b62 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -520,8 +520,7 @@ Πρόσκληση μέσω ID χρήστη Μόνο χρήστες Matrix Ευρετήριο χρηστών - Η μεταβλητή μπορεί να είναι ένα μόνο όνομα ή μια σειρά από ονόματα -\n(\"Aliki,\" + Είστε σίγουροι ότι θέλετε να προσκαλέσετε τους %s σε αυτή την συζήτηση; Λόγος Δεν εξακριβώθηκε η ταυτότητα του εξωτερικού διακομιστή. Απόκρυψη όλων των μηνυμάτων από αυτό το χρήστη; From 6388d6b91bd0b7e2dec6a8c1417f08a5de7bfc59 Mon Sep 17 00:00:00 2001 From: gkkulik Date: Fri, 8 Jan 2021 22:25:16 +0000 Subject: [PATCH 182/224] Added translation using Weblate (Silesian) --- vector/src/main/res/values-szl/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vector/src/main/res/values-szl/strings.xml diff --git a/vector/src/main/res/values-szl/strings.xml b/vector/src/main/res/values-szl/strings.xml new file mode 100644 index 0000000000..a6b3daec93 --- /dev/null +++ b/vector/src/main/res/values-szl/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 6d5e1b2285743cfbbc6dac113466ad39bd0fb4db Mon Sep 17 00:00:00 2001 From: gkkulik Date: Fri, 8 Jan 2021 22:30:19 +0000 Subject: [PATCH 183/224] Added translation using Weblate (Silesian) --- matrix-sdk-android/src/main/res/values-szl/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 matrix-sdk-android/src/main/res/values-szl/strings.xml diff --git a/matrix-sdk-android/src/main/res/values-szl/strings.xml b/matrix-sdk-android/src/main/res/values-szl/strings.xml new file mode 100644 index 0000000000..a6b3daec93 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-szl/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From ce925335250786875f9ca91194ca2d411a9800a8 Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Sat, 9 Jan 2021 00:39:24 +0000 Subject: [PATCH 184/224] Update CHANGES.md No need to gender users :) --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index ee09fc08cc..1315d006e0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,7 +6,7 @@ Features ✨: Improvements 🙌: - Add System theme option and set as default (#904, #2387) - - Warn user when he is leaving a not public room (#1460) + - Warn user when they are leaving a not public room (#1460) Bugfix 🐛: - Unspecced msgType field in m.sticker (#2580) From f4db5930095e707e960d130303677c25310c868c Mon Sep 17 00:00:00 2001 From: gradle-update-robot Date: Sat, 9 Jan 2021 01:14:35 +0000 Subject: [PATCH 185/224] Update Gradle Wrapper from 6.7.1 to 6.8. Signed-off-by: gradle-update-robot --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cdc95ef6eb..f1577bddaa 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=22449f5231796abd892c98b2a07c9ceebe4688d192cd2d6763f8e3bf8acbedeb -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip +distributionSha256Sum=a7ca23b3ccf265680f2bfd35f1f00b1424f4466292c7337c85d46c9641b3f053 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 2546061933d899b9c45ebf49bf303d8cfebdae4c Mon Sep 17 00:00:00 2001 From: kojid Date: Sat, 9 Jan 2021 20:48:34 +0000 Subject: [PATCH 186/224] Translated using Weblate (German) Currently translated at 100.0% (2018 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 7fd05a6a86..9520888278 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -2273,4 +2273,7 @@ Änderungen daran, wer die Chronik lesen kann, gellten nur für kommende Nachrichten in diesem Raum. Die Sichtbarkeit der bestehenden Chronik bleibt unverändert. Zurückziehen Hinzufügen + Mit Nachricht teilen + Erweiterte Optionen ausblenden + Erweiterte Optionen anzeigen \ No newline at end of file From a724f844f74cb9c25af1e2d0bb686f1dbd66290d Mon Sep 17 00:00:00 2001 From: Ludwig Bald Date: Fri, 8 Jan 2021 13:54:40 +0000 Subject: [PATCH 187/224] Translated using Weblate (German) Currently translated at 100.0% (2018 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 66 +++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 9520888278..5484da14eb 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -475,7 +475,7 @@ Wer kann den Chatverlauf lesen? Wer kann auf diesen Raum zugreifen? - Jeder + Jede*r Nur Mitglieder (ab dem Zeitpunkt, an dem diese Option ausgewählt wurde) Nur Mitglieder (ab dem Zeitpunkt, an dem sie eingeladen wurden) Nur Mitglieder (ab dem Zeitpunkt, an dem sie beigetreten sind) @@ -2121,7 +2121,7 @@ Bestätige PIN um die PIN zu deaktivieren Verhindere versehentliche Anrufe Bitte um Bestätigung, bevor du einen Anruf tätigst - Konfiguration + Einrichten Dir fehlt die Berechtigung in diesem Raum eine Konferenz zu starten Es ist bereits eine Konferenz aktiv! Starte eine Videokonferenz @@ -2265,7 +2265,7 @@ Nach Name oder ID suchen Gib die Erlaubnis, um auf die Kamera zu zugreifen. Um den QR-Code zu scannen, muss der Zugriff auf die Kamera erlaubt werden. - Veröffentlichte Adressen + Öffentliche Adressen Raumadressen Raumadressen und Sichtbarkeit im Raumverzeichnis ansehen und bearbeiten. Raumadresse @@ -2276,4 +2276,64 @@ Mit Nachricht teilen Erweiterte Optionen ausblenden Erweiterte Optionen anzeigen + Die Sichtbarkeit des Raums konnte nicht abgerufen werden (%1$s). + Matrix-Link + QR-Code nicht gescannt! + Inkorrekter QR code (invalide URL)! + Du kannst dir selbst keine Direktnachricht schicken! + Ändere deine aktuelle PIN + PIN ändern + Suche nach Kontakten auf Matrix + Avatar einrichten + Einverständnis wurde nicht abgegeben. + Teile diesen Code mit Leuten, damit sie ihn scannen und mit dir chatten können. + Meinen Code teilen + Mein Code + Scanne einen QR code + Das ist kein korrekter QR-Code von Matrix + 🔐️ Komm mit zu Element + Hey, schreibe mit mir auf Element: %s + Freunde einladen + Leute hinzufügen + "Thema " + Füge ein Thema hinzu + %s, um zu zeigen um was es in diesem Raum geht. + Das ist der Anfang deiner Direktnachrichten mit %s. + Das ist der Anfang dieser Konversation. + Das ist der Anfang von %s. + Du hast nicht die nötigen Berechtigungen, um die Verschlüsselung in diesem Raum zu aktivieren. + Erstelle Raum… + Manche Zeichen sind nicht zulässig + Bitte gib eine Raumadresse an + Diese Adresse ist bereits vergeben + Raumadresse + Aktivieren, wenn der Raum nur von Mitgliedern deines Homeservers zur internen Kommunikation verwendet wird. Das kann später nicht mehr geändert werden. + Begrenze Zugang zu diesem Raum (für immer!) auf Mitglieder von %s + %1$d von %2$d + QR-Code scannen, um eine neue Direktnachtricht schicken + Um Matrix-Accounts deiner bestehenden Kontakte zu finden werden Daten aus deiner Kontaktliste (Telefonnummern und Emails) an den eingestellten Identitätsserver %1$s gesendet. +\nDie Daten werden vor dem Senden gehasht, also nicht im Klartext verschickt. +\nEinverstanden\? + Keine Vorschau für diesen Raum verfügbar. Willst du direkt beitreten\? + Der Raum ist gerade nicht zugänglich. +\nVersuche es später nochmal, oder bitte einen Raum-Admin um Hilfe. + Eine neue Adresse veröffentlichen + Mit einer öffentlichen Adresse kann jede*r mit jedem Server deinem Raum beitreten. Um eine Adresse zu veröffentlichen, muss sie zuerst als lokale Adresse gesetzt sein. + Diesen Raum im Verzeichnis von %1$s veröffentlichen\? + Die Adresse \"%1$s\" nicht mehr veröffentlichen\? + Diese Adresse nicht mehr veröffentlichen + Diese Adresse veröffentlichen + Lokale Adresse hinzufügen + Dieser Raum hat keine lokalen Adressen + Füge Adressen für diesen Raum hinzu, damit andere Nutzer ihn auf %1$s finden können + Lokale Adresse + Neue öffentliche Adresse (z.B. #alias:server) + Noch keine weiteren öffentlichen Adressen vorhanden. + Noch keine weiteren öffentlichen Adressen vorhanden, füge unten eine hinzu. + Diesen Raum im Verzeichnis von %1$s veröffentlichen\? + Die Adresse \"%1$s\" löschen\? + Veröffentlichen + Andere öffentliche Adressen: + Hauptadresse + Das ist die Hauptadresse \ No newline at end of file From cdaddb15af5c9edcee98c44b485c44c31512b8c8 Mon Sep 17 00:00:00 2001 From: kojid Date: Sat, 9 Jan 2021 20:53:49 +0000 Subject: [PATCH 188/224] Translated using Weblate (German) Currently translated at 100.0% (2018 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 5484da14eb..e05375b68b 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -2311,9 +2311,9 @@ Begrenze Zugang zu diesem Raum (für immer!) auf Mitglieder von %s %1$d von %2$d QR-Code scannen, um eine neue Direktnachtricht schicken - Um Matrix-Accounts deiner bestehenden Kontakte zu finden werden Daten aus deiner Kontaktliste (Telefonnummern und Emails) an den eingestellten Identitätsserver %1$s gesendet. -\nDie Daten werden vor dem Senden gehasht, also nicht im Klartext verschickt. -\nEinverstanden\? + Um bestehende Kontakte zu finden, ist es notwendig, Ihre Kontaktdaten (Telefonnummern und/oder E-Mails) mit dem ausgewählten Identitätsserver (%1$s) zu teilen. +\n +\nFür mehr Datenschutz werden die gesendeten Daten vor dem Versenden gehasht. Keine Vorschau für diesen Raum verfügbar. Willst du direkt beitreten\? Der Raum ist gerade nicht zugänglich. \nVersuche es später nochmal, oder bitte einen Raum-Admin um Hilfe. From a9ee94e3f0227d6fe30cbb8c4acd7731a1e81212 Mon Sep 17 00:00:00 2001 From: Constantinos Miltiadis Date: Fri, 8 Jan 2021 21:49:28 +0000 Subject: [PATCH 189/224] Translated using Weblate (Greek) Currently translated at 24.2% (490 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 8400b32b62..8d8e827796 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -528,4 +528,26 @@ Λόγοι αναφοράς αυτού του περιεχομένου Ρυθμίσεις Λεπτομέρειες Δωματίου + ΚΑΛΕΣΜΕΝΟΣ/Η + Πληκτρολογείστε ταυτότητα (ID) δωματίου ή ψευδώνυμο δωματίου + Ένταξη στο δωμάτιο + Δημιουργία δωματίου + ΠΡΟΣΚΛΗΣΕΙΣ + ΧΑΜΗΛΗ ΠΡΟΤΕΡΑΙΟΤΗΤΑ + ΔΩΜΑΤΙΑ + ΣΥΜΜΕΤΟΧΗ + Η αναζήτηση σε κρυπτογραφημένα δωμάτια δεν υποστηρίζεται ακόμα. + ΑΡΧΕΙΑ + ΜΗΝΥΜΑΤΑ + ΔΩΜΑΤΙΑ + Κανένα αποτέλεσμα + Φιλτράρισμα αποβεβλημένων χρηστών + Φιλτράρισμα μελών δωματίου + Εύρεση + Ακύρωση Λήψης + Ακύρωση Αποστολής + Παραποιημένη ταυτότητα (ID). Πρέπει να είναι διεύθυνση ηλ. ταχυδρομίου ή ταυτότητα (ID) τύπου Matrix, όπως @localpart:domain\' + Αποδεκτείτε το πιστοποιητικό εαν ο διαχειριστής του διακομιστή έχει εκδόσει ένα αποτύπωμα που ταιριάζει με το παρά πάνω. + Το πιστοποιτικό έχει αλλάξει από ένα προηγούμενο αξιόπιστο, σε ένα αναξιόπιστο. Ο διακομιστής ενδέχεται να έχει αλλάξει το πιστοποιητικό του. Επικοινωνείστε με το διαχειριστή του διακομιστή για το αναμενόμενο αποτύπωμα. + Το πιστοποιητικό έχει αλλάξει από αυτό που εμπιστεύθηκε προηγουμένως η συσκευή σας. Αυτό είναι ΑΚΡΩΣ ΑΣΥΝΗΘΙΣΤΟ. Προτείνεται να ΜΗΝ ΑΠΟΔΕΚΤΕΙΤΕ το νεο πιστοποιητικό. \ No newline at end of file From a8e4be914689595a4fe3e52cce9c2307bc42ef4f Mon Sep 17 00:00:00 2001 From: Andreas Kelemen Date: Fri, 8 Jan 2021 21:21:50 +0000 Subject: [PATCH 190/224] Translated using Weblate (Greek) Currently translated at 24.2% (490 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/el/ --- vector/src/main/res/values-el/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 8d8e827796..c5242447c9 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -524,6 +524,7 @@ Λόγος Δεν εξακριβώθηκε η ταυτότητα του εξωτερικού διακομιστή. Απόκρυψη όλων των μηνυμάτων από αυτό το χρήστη; +\n \nΑυτή η ενέργεια θα επανεκκινήσει την εφαρμογή και ίσως πάρει λίγο χρόνο. Λόγοι αναφοράς αυτού του περιεχομένου Ρυθμίσεις From e22e70c5ba4bd25bc8d1513fdc688aa8b7b06f72 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Sat, 9 Jan 2021 03:57:27 +0000 Subject: [PATCH 191/224] Translated using Weblate (Ukrainian) Currently translated at 61.5% (1242 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/uk/ --- vector/src/main/res/values-uk/strings.xml | 442 +++++++++++----------- 1 file changed, 231 insertions(+), 211 deletions(-) diff --git a/vector/src/main/res/values-uk/strings.xml b/vector/src/main/res/values-uk/strings.xml index b4ad0d4bd9..a298fb6cd3 100644 --- a/vector/src/main/res/values-uk/strings.xml +++ b/vector/src/main/res/values-uk/strings.xml @@ -27,7 +27,7 @@ Надіслати ще раз Прибрати Цитата - Поширити + Поділитися Пізніше Переслати Постійне посилання @@ -135,8 +135,8 @@ Пароль Новий пароль Логін - Email адреса - Email адреса (додаткова) + Адреса електронної пошти + Адреса електронної пошти (додаткова) Номер телефону Номер телефону (додатковий) Повторіть пароль @@ -271,13 +271,13 @@ Запросити Залишити цю кімнату Вилучити з цієї кімнати - Забанити - Розбанити + Заблокувати + Розблокувати Зробити звичайним користувачем Зробити модератором Зробити адміністратором - Сховати всі повідомлення користувача - Показати всі повідомлення користувача + Ігнорувати користувача + Перестати ігнорувати ID користувача, ім\'я або email Згадати Показати Список Пристроїв @@ -311,7 +311,7 @@ Довіряти Не довіряти Вийти - Ігнорувати + Нехтувати Відбиток (%s): Не вдалося перевірити сертифікат сервера. Це може означати, що хтось зі злими намірами намагається перехопити ваш трафік або ваш телефон не довіряє сертифікату, наданому віддаленим сервером. @@ -391,7 +391,7 @@ Запрошення до кімнат Виклики Повідомлення від бота - Запускати при старті системи + Запускати під час завантаження Фонова синхронізація Увімкнути фонову синхронізацію Таймаут синхронізації @@ -538,13 +538,13 @@ Ключ ідентичності Curve25519 Заявлений ключ відбитка пальця Ed25519 Алгоритм - ID сесії + ID сеансу Помилка розшифрування Інформація про пристрій відправника Назва пристрою - Ім\'я - ID пристрою - Ключ пристрою + Загальнодоступна назва + ID сеансу + Ключ сеансу Перевірка Відбиток пальця Ed25519 Експортувати E2E ключі кімнати @@ -630,7 +630,7 @@ Ваш неперевірений пристрій \'%s\' править ключі шифрування. Почати перевірку Поділитись без перевірки - Ігнорувати запит + Знехтувати запитом Помилка виконання команди Команду %s не розпізнано @@ -659,10 +659,10 @@ Синхронізація… Всі повідомлення (гучно) Всі повідомлення - Тільки упоминания - Без звука + Лише згадки + Без звуку Додати ярлик на головний екран - Конфіденційність сповіщень + Приватність сповіщень Нормальний Відправити наліпку Відправити стікер @@ -681,7 +681,7 @@ %d участників - Користувачів з забороною буде вилучено з цієї кімнати й вони не зможуть приєднатися знову. + Заблокованих користувачів буде вилучено з цієї кімнати й вони не зможуть приєднатися знову. %d нове повідомлення %d нових повідомленя @@ -690,9 +690,9 @@ Обмежена конфіденційність Програма потребує дозвіл на роботу у фоновому режимі - • Повідомлення відправляються через Google Cloud Messaging - • Повідомлення містять тільки метаданні - • Зміст сповіщення був надійно віднайдений просто на домашньому сервері Matrix + • Сповіщення надсилаються через Google Cloud Messaging + • Сповіщення містять лише метадані + • Зміст повідомлення було надійно розміщено на домашньому сервері Matrix Ліцензії сторонніх виробників Завантажити Говорити @@ -904,7 +904,7 @@ +%d %d+ Все одно подзвонити - Копнути + Викинути Причина Попередній перегляд посилань у чаті, у разі якщо Ваш сервер підтримує таку можливість. Надсилати сповіщення про набір повідомлення @@ -925,8 +925,8 @@ Markdown вимкнено. Виклики Використовувати стандартний рингтон Element для вхідних викликів - Рингтон вхідного виклику - Оберіть рингтон для викликів: + Мелодія вхідного виклику + Виберіть мелодію викликів: Прийняти Будь ласка, ознайомтесь та прийміть правила цього серверу: Позначити як прочитане @@ -947,7 +947,7 @@ Повідомлення… Ви не маєте доступу до цього повідомлення Очікуємо повідомлення, це може тривати певний час - Вхідний виклик (%s) + Активний виклик (%s) Не вдається отримати домашній сервер за цією URL-адресою, перевірте його Це недійсна адреса сервера Matrix Ця URL-адреса недоступна, перевірте її @@ -976,7 +976,7 @@ Прийняти Відмовити Огляд - Ігнорувати + Знехтувати Перервати Готово Пропустити @@ -1016,7 +1016,7 @@ Запобігати випадковим викликам Мені не потрібні мої зашифровані повідомлення Скасувати зміни - SSL помилка. + Помилка SSL. Ви не можете здійснити дзвінок із самим собою, дочекайтесь, доки інші учасники приймуть ваше запрошення ФАЙЛИ В цій кімнаті немає медіа @@ -1155,31 +1155,31 @@ \n \nЗупинити змінювання пароля\? Ви успішно змінили налаштування кімнати - Тепер ваші ключі шифрування резервно копіюються у фоновому режимі на домашній сервер. Початкове резервне копіювання може зайняти кілька хвилин. + Тепер резервні копії ваших ключів шифрування створюються у фоновому режимі на домашній сервер. Початкове резервне копіювання може тривати кілька хвилин. Резервне копіювання розпочато Неочікувана помилка Ключ відновлення - Створення ключа відновлення за допомогою парольної фрази, цей процес може зайняти кілька секунд. + Створення ключа відновлення за допомогою парольної фрази, цей процес може тривати кілька секунд. Поділитися ключем відновлення з… - Будь ласка, зробіть копію - Стій + Будь ласка, створіть копію + Стоп Замінити - Схоже, у вас вже є резервне копіювання ключа налаштування з іншого сеансу. Ви хочете замінити його тим, який ви створюєте\? + Схоже у вас вже є резервна копія ключа налаштування з іншого сеансу. Хочете замінити його тим, який ви створюєте\? Резервна копія вже існує на вашому HomeServer Ключ відновлення збережено. - Ключ відновлення збережено у папці \"% s\". + Ключ відновлення збережено до теки «%s». \n \nПопередження: цей файл може бути видалено, якщо програму видалено. Зберегти як файл - Поділіться - Збережіть ключ відновлення - Я зробив копію + Поділитися + Зберегти ключ відновлення + Я створив копію Готово - Тримайте ключ відновлення десь дуже надійно, наприклад, менеджер паролів (або сейф) - Ваш ключ відновлення - це мережа безпеки - ви можете використовувати його для відновлення доступу до ваших зашифрованих повідомлень, якщо ви забудете свою парольну фразу. -\nТримайте ключ відновлення десь дуже надійно, наприклад, менеджер паролів (або сейф) - Ваші ключі резервно копіюються. - Успіху! + Зберігайте ключ відновлення десь дуже надійно, наприклад, у менеджері паролів (або сейфі) + Ваш ключ відновлення — це мережа безпеки — ви можете використовувати його для відновлення доступу до ваших зашифрованих повідомлень, якщо ви забудете свою парольну фразу. +\nТримайте ключ відновлення десь дуже надійно, наприклад, у менеджері паролів (або сейфі) + Створюється резервна копія ключів. + Успішно ! (Додатково) Налаштування за допомогою ключа відновлення Або захистіть свою резервну копію за допомогою ключа відновлення, зберігаючи її десь у безпеці. Створення резервної копії @@ -1190,279 +1190,299 @@ Захистіть свою резервну копію за допомогою парольної фрази. Експорт ключів вручну Почніть використовувати резервне копіювання ключів - Повідомлення в зашифрованих кімнатах захищаються наскрізним шифруванням. Тільки ви та одержувач (и) маєте ключі для читання цих повідомлень. + Повідомлення в зашифрованих кімнатах захищено наскрізним шифруванням. Тільки ви та одержувачі маєте ключі для читання цих повідомлень. \n -\nНадійно створіть резервну копію клавіш, щоб не втратити їх. +\nБезпечно створюйте резервні копії ключів, щоб не втратити їх. Ніколи не втрачайте зашифровані повідомлення - Немає сесії Matrix + Немає доступного сеансу Matrix Видаліть парольну фразу, якщо хочете, щоб Element створив ключ відновлення. Парольна фраза занадто слабка Введіть парольну фразу Не знайдено дійсного файлу .apk сервісів Google Play. Сповіщення можуть працювати неправильно. Введіть ім’я користувача. - Безмовний - Ігнорувати + Беззвучно + Знехтувати Запит на розподіл ключів - Поділіться + Поділитися Перевірити Неперевірений сеанс запитує ключі шифрування. -\nНазва сесії:% 1 $ s -\nВостаннє бачено:% 2 $ s -\nЯкщо ви не ввійшли в інший сеанс, проігноруйте цей запит. - Нова сесія вимагає ключів шифрування. -\nНазва сесії:% 1 $ s -\nВостаннє бачено:% 2 $ s -\nЯкщо ви не ввійшли в інший сеанс, проігноруйте цей запит. - Для продовження потрібно прийняти Умови цієї послуги. +\nНазва сеансу: %1$s +\nОстанні відвідини: %2$s +\nЯкщо ви не ввійшли в інший сеанс, знехтуйте цим запитом. + Новий сеанс запитує ключі шифрування. +\nНазва сеансу: %1$s +\nОстанні відвідини: %2$s +\nЯкщо ви не ввійшли в інший сеанс, знехтуйте цим запитом. + Для продовження потрібно прийняти Умови користування цією службою. Немає активних віджетів - Керуйте інтеграціями + Керувати інтеграціями Менеджер інтеграції не налаштовано. - Прочитайте захищені DRM засоби масової інформації - Використовуйте мікрофон - Використовуйте камеру + Читати захищені DRM засоби масової інформації + Використовувати мікрофон + Використовувати камеру Заблокувати все - Дозвольте + Дозволити Цей віджет хоче використовувати такі ресурси: На жаль, конференц-дзвінки з Jitsi не підтримуються на старих пристроях (пристрої з ОС Android нижче 5.0) Ідентифікатор кімнати Ідентифікатор віджета Ваша тема Ваш ідентифікатор користувача - URL-адреса вашого аватара - Ваше відображуване ім\'я + URL-адреса зображення профілю + Ваше видиме ім\'я Скасувати доступ для мене Відкрити в браузері - Перезавантажте віджет + Перезавантажити віджет Не вдалося завантажити віджет. -\n% s - Його використання може обмінюватися даними з% s: - За його допомогою можна встановити файли cookie та обмінюватися даними з% s: +\n%s + Використання може спричинити обмін даними з %s: + За його використання може бути встановлено файли cookie та відбуватися обмін даними з %s: Цей віджет додав: Завантажити віджет Віджет Активні віджети - ПЕРЕГЛЯН - % 1 $ s:% 2 $ s% 3 $ s - % 1 $ s:% 2 $ s - ** Не вдалося надіслати - відкрийте кімнату + ПОДАННЯ + %1$s: %2$s %3$s + %1$s: %2$s + ** Не вдалося надіслати — відкрийте кімнату Я Нове запрошення Нові повідомлення Кімната Нова подія - % 1 $ s та% 2 $ s - % 1 $ s у% 2 $ s та% 3 $ s + %1$s й %2$s + %1$s в %2$s та %3$s - повідомлення - повідомлення - повідомлення - повідомлення + %d сповіщення + %d сповіщення + %d сповіщень + %d сповіщень - повідомлення - повідомлення - повідомлення - повідомлення + %1$s: %2$d повідомлення + %1$s: %2$d повідомлення + %1$s: %2$d повідомлень + %1$s: %2$d повідомлень - запрошення - запрошення - запрошення - запрошення + %d запрошення + %d запрошення + %d запрошень + %d запрошень - невідомий ip + невідома ip - Ключ% 1 $ d /% 2 $ d імпортовано з успіхом. - ключі, імпортовані з успіхом. - ключі, імпортовані з успіхом. - ключі, імпортовані з успіхом. + %1$d/%2$d ключ успішно імпортовано. + %1$d/%2$d ключі успішно імпортовано. + %1$d/%2$d ключів успішно імпортовано. + %1$d/%2$d ключів успішно імпортовано. Керування резервною копією ключів Відновлення зашифрованих повідомлень - Ключі успішно експортовані - Публічну назву сеансу бачать люди, з якими ви спілкуєтесь - Публічне ім’я (видиме людям, з якими спілкуєтесь) + Ключі успішно експортовано + Загальнодоступну назву сеансу бачать люди, з якими ви спілкуєтесь + Загальнодоступна назва (видима людям, з якими спілкуєтесь) - % d заборонений користувач - % d заборонених користувачів - % d заборонених користувачів - % d заборонених користувачів + %d заборонений користувач + %d заборонені користувачі + %d заборонених користувачів + %d заборонених користувачів - Не вдається отримати поточну видимість каталогу кімнат (% 1 $ s). - Опублікувати цю кімнату для всіх у каталозі кімнат% 1 $ s\? + Не вдалося отримати поточну видимість каталогу кімнат (%1$s). + Опублікувати цю кімнату для всіх у каталозі кімнат %1$s\? Скасувати публікацію цієї адреси - Опублікуйте цю адресу - Додайте місцеву адресу - У цій кімнаті немає місцевих адрес - Встановіть адреси для цієї кімнати, щоб користувачі могли знаходити цю кімнату через ваш домашній сервер (% 1 $ s) - Місцеві адреси - Нова опублікована адреса (наприклад, #alias: server) + Опублікувати цю адресу + Додати локальну адресу + Кімната не має локальної адреси + Встановіть адреси для цієї кімнати, щоб користувачі могли знаходити цю кімнату через ваш домашній сервер (%1$s) + Локальні адреси + Нова опублікована адреса (наприклад, #alias:server) Інших опублікованих адрес поки що немає. - Інших опублікованих адрес поки що немає, додайте одну нижче. - Опублікувати цю кімнату для всіх у каталозі кімнат% 1 $ s\? - Видалити адресу \"% 1 $ s\"\? - Скасувати публікацію адреси \"% 1 $ s\"\? + Інших опублікованих адрес поки що немає, додайте якусь внизу. + Опублікувати цю кімнату для всіх у каталозі кімнат %1$s\? + Видалити адресу \"%1$s\"\? + Скасувати публікацію адреси \"%1$s\"\? Опублікувати - Опублікуйте нову адресу вручну + Опублікувати нову адресу вручну Інші опубліковані адреси: Основна адреса Це основна адреса - Опубліковані адреси може використовувати будь-хто на будь-якому сервері для приєднання до вашої кімнати. Щоб опублікувати адресу, її потрібно спочатку встановити як локальну адресу. - Опубліковані адреси + Загальнодоступні адреси може використовувати будь-хто на будь-якому сервері для приєднання до вашої кімнати. Щоб опублікувати адресу спочатку встановіть її локальною адресою. + Загальнодоступні адреси Адреси кімнат Перегляньте адреси цієї кімнати та керовані ними, а також їх видимість у каталозі кімнати. - Адреси номерів - Доступ до номера - Зміни щодо того, хто може читати історію, стосуватимуться лише майбутніх повідомлень у цій кімнаті. Видимість існуючої історії залишиться незмінною. + Адреси кімнат + Доступ до кімнати + Зміни щодо тих, хто може читати історію, стосуватимуться лише майбутніх повідомлень у цій кімнаті. Видимість наявної історії залишиться незмінною. Відтворити звук затвора - Вибирайте - Медіа-джерело за замовчуванням - Вибирайте - Стиснення за замовчуванням - ЗМІ - Додаткова інформація:% s + Вибрати + Типове джерело медіа + Вибрати + Типове стиснення + Медіа + Додаткові відомості: %s Під час підтвердження номера телефону сталася помилка. Паролі не збігаються Пароль не дійсний Оновити пароль Під час підтвердження вашої адреси електронної пошти сталася помилка. Увімкніть для цього параметр \"Дозволити інтеграцію\" у налаштуваннях. - Інтеграція вимкнена - Менеджер інтеграції + Інтеграцію вимкнено + Керування інтеграцією Дозволити інтеграції Режим збереження даних застосовує певний фільтр, тому оновлення присутності та сповіщення про введення фільтруються. - Дайте дозвіл - Для отримання надійних сповіщень елементу потрібно підтримувати з’єднання у фоновому режимі з незначним ударом. -\nНа наступному екрані вам буде запропоновано дозволити Element завжди працювати у фоновому режимі, прийміть. + Надати дозвіл + Для отримання надійних сповіщень Element повинен підтримувати з’єднання у фоновому режимі з незначним споживанням даних. +\nНа наступному екрані вам буде запропоновано дозволити Element завжди працювати у фоновому режимі, погодьтеся. Фонове з’єднання Це замінить ваш поточний ключ або фразу. - Створіть новий ключ безпеки або встановіть нову фразу безпеки для існуючої резервної копії. - Захистіть від втрати доступу до зашифрованих повідомлень та даних, створивши резервну копію ключів шифрування на своєму сервері. - Налаштуйте на цьому пристрої - Скиньте безпечне резервне копіювання - Налаштуйте безпечне резервне копіювання - Управління + Створіть новий ключ безпеки або встановіть нову фразу безпеки для наявної резервної копії. + Захистіться від втрати доступу до зашифрованих повідомлень та даних створенням резервної копії ключів шифрування на своєму сервері. + Налаштувати на цьому пристрої + Скинути безпечне резервне копіювання + Налаштувати безпечне резервне копіювання + Керувати Безпечне резервне копіювання - Включає події запрошення / приєднання / зліва / удару / заборони та зміни аватара / відображуваного імені. - Показати події держав-членів + Включає події запрошення/приєднання/виходу/видалення/заборони та зміни зображень профілю/видимих імен. + Показати стан подій учасників кімнати Управління ключами криптографії - Використовуйте Integration Manager для керування ботами, мостами, віджетами та пакетами наклейок. -\nМенеджери інтеграції отримують дані конфігурації та можуть змінювати віджети, надсилати запрошення до кімнати та встановлювати рівні потужності від вашого імені. + Використовуйте Менеджер інтеграції для керування ботами, мостами, віджетами та пакетами наклейок. +\nМенеджери інтеграції отримують дані конфігурації та можуть змінювати віджети, надсилати запрошення до кімнати та надавати права від вашого імені. Інтеграції - % d секунди - % d секунди - % d секунди - % d секунди + %d секунда + %d секунди + %d секунд + %d секунд - % s -\nСинхронізація може бути відкладена залежно від ресурсів (акумулятор) або стану пристрою (сплячий режим). + %s +\nСинхронізацію може бути відкладено залежно від ресурсів (акумулятор) або стану пристрою (режим сну). Бажаний інтервал синхронізації Не вдалося оновити налаштування. Ви не отримуватимете сповіщення про вхідні повідомлення, коли програма перебуває у фоновому режимі. Немає фонової синхронізації - Елемент періодично синхронізуватиметься у фоновому режимі в певний час (налаштовується). -\nЦе вплине на використання радіо та акумулятора, з’явиться постійне сповіщення про те, що Element прослуховує події. + Element періодично синхронізуватиметься у фоновому режимі в певний час (налаштовується). +\nЦе вплине на використання радіо та акумулятора, з’явиться постійне сповіщення про те, що Element очікує на події. Оптимізовано для реального часу - Елемент синхронізується у фоновому режимі таким чином, щоб зберегти обмежені ресурси пристрою (акумулятор). -\nЗалежно від стану ресурсу вашого пристрою, синхронізація може бути відкладена операційною системою. + Element синхронізується у фоновому режимі так, щоб зберегти обмежені ресурси пристрою (акумулятор). +\nЗалежно від стану ресурсів вашого пристрою, синхронізацію може бути відкладено операційною системою. Оптимізовано для батареї Режим фонової синхронізації - Додатки не потребують підключення до HomeServer у фоновому режимі, це має зменшити споживання батареї - Ігнорувати оптимізацію - Якщо користувач залишає пристрій відключеним та нерухомим протягом певного періоду часу, при вимкненому екрані, пристрій переходить у режим дрімання. Це запобігає доступу програм до мережі та відкладає їх завдання, синхронізацію та стандартні сигнали тривоги. - Оптимізація акумулятора не впливає на елемент. + Застосунки не потребують з\'єднання з HomeServer у фоновому режимі, це має скоротити споживання батареї + Нехтувати оптимізацією + Якщо користувач залишає пристрій від\'єднаним та нерухомим впродовж певного часу з вимкненим екраном, пристрій переходить у режим дрімання. Це запобігає доступу програм до мережі та відкладає їх завдання, синхронізацію та стандартні сигнали тривоги. + Оптимізація акумулятора не впливає на Element. Оптимізація акумулятора Вимкнути обмеження - Фонові обмеження ввімкнено для елемента. -\nРобота, яку намагається виконати програма, буде агресивно обмежена, поки вона перебуває у фоновому режимі, і це може вплинути на сповіщення. -\n% 1 $ s - Фонові обмеження для елемента вимкнено. Цей тест слід проводити з використанням мобільних даних (без Wi-Fi). -\n% 1 $ s + Фонові обмеження ввімкнено для Element. +\nРобота, яку намагається виконати застосунок, буде агресивно обмежена, доки вона перебуває у фоновому режимі й це може вплинути на сповіщення. +\n%1$s + Фонові обмеження для Element вимкнено. Цю перевірку варто виконувати з використанням мобільних даних (без Wi-Fi). +\n%1$s Перевірте фонові обмеження - Увімкніть Пуск під час завантаження - Послуга не запуститься при перезавантаженні пристрою, ви не будете отримувати сповіщення, доки Element не буде відкрито один раз. - Сервіс почнеться після перезапуску пристрою. - Почніть із завантаження + Увімкніть Запуск під час завантаження + Служба не запуститься під час перезавантаження пристрою, ви не отримуватимете сповіщень, доки Element не буде відкрито. + Служба запуститься після перезапуску пристрою. + Запускати під час завантаження Помилка перезапуску служби - Сервіс був убитий і перезапущений автоматично. + Службу зупинено й перезапущено автоматично. Автоматичний перезапуск служби сповіщень - Запустіть службу + Запуск служби Служба сповіщень не працює. \nСпробуйте перезапустити програму. Служба сповіщень працює. Служба сповіщень - Повідомлення натиснуто! + Сповіщення натиснено! Клацніть на сповіщення. Якщо ви не бачите сповіщення, перевірте налаштування системи. - Відображення сповіщень + Показ сповіщень Ви переглядаєте сповіщення! Клацніть на мене! - Не вдалося отримати push. Рішенням може бути перевстановлення програми. - Додаток отримує PUSH - Додаток чекає PUSH - Тестовий поштовх - Не вдалося зареєструвати маркер FCM на HomeServer: -\n% 1 $ s - Токен FCM успішно зареєстрований на HomeServer. + Не вдалося отримати push. Рішенням може бути перевстановлення застосунку. + Застосунок отримує PUSH + Застосунок очікує PUSH + Випробувальне надсилання + Не вдалося зареєструвати токен FCM на HomeServer: +\n%1$s + Токен FCM успішно зареєстровано на HomeServer. Реєстрація токена Додати обліковий запис - [% 1 $ s] -\nЦя помилка вийшла з-під контролю Element. На телефоні немає облікового запису Google. Відкрийте менеджер облікових записів і додайте обліковий запис Google. - [% 1 $ s] -\nЦя помилка вийшла з-під контролю Element. Це може статися з кількох причин. Можливо, це спрацює, якщо ви спробуєте пізніше, ви також можете перевірити, чи не обмежена служба Google Play щодо використання даних у налаштуваннях системи, чи правильний годинник вашого пристрою, або це може статися на користувацькому ПЗУ. - [% 1 $ s] -\nЦя помилка вийшла з-під контролю Element, і за даними Google, ця помилка вказує на те, що на пристрої зареєстровано забагато програм у FCM. Помилка виникає лише у випадках, коли додатків надзвичайно багато, тому вона не повинна впливати на звичайного користувача. - Не вдалося отримати маркер FCM: -\n% 1 $ s - Успішно отримано маркер FCM: -\n% 1 $ s + [%1$s] +\nЦя помилка не підконтрольна Element. На телефоні немає облікового запису Google. Відкрийте менеджер облікових записів і додайте обліковий запис Google. + [%1$s] +\nЦя помилка не підконтрольна Element. Це може статися з кількох причин. Можливо все запрацює, якщо ви спробуєте пізніше, ви також можете перевірити, чи не обмежено використання даних для служби Google Play в налаштуваннях системи, чи правильний годинник вашого пристрою, або це може статися в користувацькому ROM. + [%1$s] +\nЦя помилка не підконтрольна Element й за даними Google, вона вказує на те, що на пристрої зареєстровано забагато програм у FCM. Помилка виникає лише у випадках, коли встановлено надзвичайно багато застосунків, тому вона не повинна впливати на звичайного користувача. + Не вдалося отримати токен FCM: +\n%1$s + Токен FCM отримано успішно: +\n%1$s Токен Firebase - Виправити послуги Play - Element використовує сервіси Google Play для доставки push-повідомлень, але, схоже, він налаштований неправильно: -\n% 1 $ s - Відкрийте Налаштування + Виправити служби Play + Element використовує сервіси Google Play для доставлення push-сповіщень, але, схоже, його налаштовано неправильно: +\n%1$s + Відкрити Налаштування Сповіщення вимкнено в налаштуваннях системи. \nБудь ласка, перевірте налаштування системи. - Один або кілька тестів не пройшли, надішліть звіт про помилку, щоб допомогти нам розслідувати. - Одне або кілька тестів не вдалося, спробуйте запропоновані виправлення. - Основна діагностика в порядку. Якщо ви все ще не отримуєте сповіщення, надішліть звіт про помилку, щоб допомогти нам розслідувати. - Важливість повідомлення за подією + Одну або кілька перевірок не пройдено, надішліть звіт про помилку, щоб допомогти нам розслідувати це. + Одну або кілька перевірок не пройдено, спробуйте запропоновані виправлення. + Основна діагностика в порядку. Якщо ви й далі не отримуєте сповіщень, надішліть звіт про помилку, щоб допомогти нам розслідувати це. + Важливість сповіщень за подією Переконайтеся, що ви натиснули посилання в електронному листі, який ми надіслали вам. - Видалити% s\? + Вилучити %s\? Потрібна автентифікація Це неможливо зробити за допомогою Element mobile Підтвердити пароль Фільтрувати заборонених користувачів - Скасування заборони користувачеві дозволить їм знову приєднатися до кімнати. + Скасування блокування користувача дозволить їм знову приєднатися до кімнати. Розблокувати користувача - Причина заборони - Заборонити користувача - нога користувач видалить їх з цієї кімнати. + Причина блокування + Заблокувати користувача + викидання користувачів прибере їх з цієї кімнати. \n -\nЩоб запобігти їх повторному приєднанню, замість цього слід заборонити їх. - Причина для удару - Удар користувача +\nЩоб запобігти їх повторному приєднанню, замість цього слід заблокувати їх. + Причина викидання + Викинути користувача Дійсно скасувати запрошення для цього користувача\? Скасувати запрошення - Ігнорування цього користувача знову покаже всі повідомлення від нього. - Ігнорувати користувача - Ігноруючи цього користувача, його повідомлення буде видалено з кімнат, якими ви ділитесь. + Зняття ігнорування з цього користувача знову покаже всі повідомлення від нього. + Не ігнорувати користувача + Ігнорування цього користувача призведе до видалення його повідомлень з кімнат, якими ви ділитесь. \n \nВи можете будь-коли змінити цю дію в загальних налаштуваннях. Ігнорувати користувача - Знизити - Ви не зможете скасувати цю зміну, оскільки знижуєтеся, якщо ви останній привілейований користувач у кімнаті, неможливо буде повернути собі привілеї. + Понизити + Ви не зможете скасувати цю зміну, оскільки понижуєте свої права, якщо ви останній привілейований користувач у кімнаті, неможливо буде повернути собі привілеї. Понизитися\? Додайте сервер ідентифікації у свої налаштування, щоб виконати цю дію. - Дозвольте доступ до ваших контактів. - Щоб відсканувати QR-код, потрібно дозволити доступ до камери. - Повернутися до дзвінка - Триває відеодзвінок… - Використовуватиме% s як допоміжний, коли ваш домашній сервер не пропонує такого (ваша IP-адреса буде надана під час дзвінка) - Дозволити сервер допоміжних викликів - Ваш пристрій використовує застарілий протокол безпеки TLS, вразливий до атак, для вашої безпеки ви не зможете підключитися - Помилка SSL: особа однолітка не підтверджена. - Встановіть електронну адресу для відновлення облікового запису. Використовуйте пізніше електронну пошту або телефон, щоб люди, які вас знають, могли їх відкрити. - Встановіть електронну адресу для відновлення облікового запису. Використовуйте пізніше електронну пошту або телефон, щоб люди, які вас знають, могли їх відкрити. + Дозволити доступ до ваших контактів. + Щоб сканувати QR-код необхідно дозволити доступ до камери. + Повернутися до виклику + Триває відеовиклик… + Використовуватиме %s допоміжним, коли ваш домашній сервер не пропонує такого (вашу IP-адресу буде надана під час виклику) + Дозволити допоміжний сервер викликів + Ваш пристрій використовує застарілий протокол безпеки TLS, вразливий до атак, для вашої безпеки ви не зможете під\'єднатися + Помилка SSL: особу співрозмовника не підтверджено. + Встановіть електронну адресу для відновлення облікового запису. Використовуйте пізніше електронну пошту або телефон, щоб люди, які вас знають, могли знайти вас за нею. + Встановіть електронну адресу для відновлення облікового запису. Використовуйте пізніше електронну пошту або телефон, щоб люди, які вас знають, могли знайти вас за нею. Встановіть телефон, а пізніше, щоб його могли побачити люди, які вас знають. - Встановіть електронну адресу для відновлення облікового запису, а пізніше, щоб вона була необов’язковою для пошуку людьми, які вас знають. + Встановіть електронну адресу для відновлення облікового запису, а пізніше, щоб вона була додатковою для пошуку людьми, які вас знають. + Номер телефону (додатковий) + Номер телефону + Без звуку + Лише згадки + Всі повідомлення + Всі повідомлення (гучно) + Ігнорувати користувача + Перестати ігнорувати + Підпис + Алгоритм + Версія + Налаштувати безпечне резервне копіювання + Використати ключ безпеки + Налаштувати + Захистіться від втрати доступу до зашифрованих повідомлень та даних створенням резервної копії ключів шифрування на своєму сервері. + Новий пароль + Увага! + Адреса + Ви можете втратити доступ до своїх повідомлень, якщо вийдете з облікового запису або загубите цей пристрій. + Ви впевнені\? \ No newline at end of file From e75d25f00c7a95f3d6fc1e0697bab250d5ebf5b2 Mon Sep 17 00:00:00 2001 From: linsui Date: Sun, 10 Jan 2021 09:17:40 +0000 Subject: [PATCH 192/224] Translated using Weblate (Chinese (Simplified)) Currently translated at 95.9% (1936 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hans/ --- vector/src/main/res/values-zh-rCN/strings.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml index 8300bf2232..114519505e 100644 --- a/vector/src/main/res/values-zh-rCN/strings.xml +++ b/vector/src/main/res/values-zh-rCN/strings.xml @@ -2152,4 +2152,21 @@ 如需扫描二维码,您须允许相机访问权限。 没有更多结果 开始畅聊 + 删除地址 \"%1$s\"? + 取消发布地址 \"%1$s\"? + 发布 + 手动发布新地址 + 其它发布的地址: + 主地址 + 这是主地址 + 发布的地址可以被任何服务器上的任何人用来加入您的聊天室。要发布一个地址,它必须先被设为一个本地地址。 + 发布的地址 + 聊天室地址 + 查看和管理此聊天室的地址,以及它在聊天室目录中的可见性。 + 聊天室地址 + 聊天室访问 + 改成谁都可以阅读历史只会应用于此聊天室未来的消息。已经存在的历史消息的可见性将不会改变。 + 发送密钥共享请求历史记录 + 取消发布 + 添加 \ No newline at end of file From 48f03c095390abb38f6ce913a998a5c2b05193b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Sun, 10 Jan 2021 19:25:38 +0000 Subject: [PATCH 193/224] Translated using Weblate (Hebrew) Currently translated at 50.4% (1018 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 366 ++++++++++++++++++++++ 1 file changed, 366 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 11329fe384..b37c8fd70b 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -395,4 +395,370 @@ הודעות לא נשלחו. %1$s או %2$s עכשיו\? הקישוריות לשרת אבדה. שלח תשובה (לא מוצפן) … + יעדי התראות + ניהול מפתחות קריפטוגרפיה + קריפטוגרפיה + השתמש במנהל שילוב לניהול בוטים, גשרים, ווידג\'טים וחבילות מדבקות. +\nמנהלי אינטגרציה מקבלים נתוני תצורה ויכולים לשנות ווידג\'טים, לשלוח הזמנות לחדר ולהגדיר רמות כוח מטעמכם. + אינטגרציות + מתקדם + אחר + משתמשים שמתעלמים מהם + התראות + הגדרות משתמש + נקה מטמון מדיה + נקה את זיכרון המטמון + שמור על מדיה + מדיניות הפרטיות + זכויות יוצרים + התראות צד שלישי + תנאים והגבלות + גרסת olm + גִרְסָה + + % d שנייה + % d שניות + % d שניות + % d שניות + + עיכוב בין כל סינכרון + % s +\nהסנכרון עשוי להידחות בהתאם למשאבים (סוללה) או מצב ההתקן (שינה). + מרווח סינכרון מועדף + פסק-זמן לבקשה לסנכרון + אפשר סנכרון רקע + החל באתחול + עדכון ההגדרות נכשל. + לא תקבל הודעה על הודעות נכנסות כאשר האפליקציה ברקע. + אין סנכרון רקע + אלמנט יסונכרן ברקע מעת לעת בזמן מדויק (ניתן להגדרה). +\nזה ישפיע על השימוש ברדיו ובסוללה, תוצג הודעה קבועה לפיה אלמנט מאזין לאירועים. + מותאם לזמן אמת + אלמנט יסונכרן ברקע באופן שישמור על המשאבים המוגבלים של המכשיר (סוללה). +\nבהתאם למצב משאבי המכשיר שלך, ייתכן שהסנכרון יידחה על ידי מערכת ההפעלה. + מותאם לסוללה + מצב סנכרון רקע + סנכרון רקע + הודעות שנשלחו על ידי בוט + הזמנות לשיחות + כשאני מוזמן לחדר + הודעות בצ\'אטים קבוצתיים + הודעות בצ\'אטים אחד-על-אחד + הודעות שמכילות את שם המשתמש שלי + הודעות שמכילות את שם התצוגה שלי + בחר צבע LED, רטט, צליל … + הגדר התראות שקטות + הגדר התראות על שיחות + הגדר תצורה של התראות רועשות + הדלק את המסך למשך 3 שניות + אפשר התראות עבור מושב זה + אפשר התראות עבור חשבון זה + צליל התראה + • התראות <b> לא יציגו את תוכן ההודעה </ b>not show message content + • התראות מכילות <b> נתוני ליבה והודעות </ b>meta and message data + • תוכן ההודעה של ההודעה <b> ממוקם בצורה מאובטחת ישירות משרת הבית של מטריקס </ b>located securely direct from the Matrix homeserver + • התראות מכילות רק נתוני ליבה + • התראות נשלחות באמצעות Firebase Cloud Messaging + היישומים <b> לא </ b> צריכים להתחבר ל- HomeServer ברקע, זה אמור להפחית את השימוש בסוללהnot need to connect to the HomeServer in the background, it should reduce battery usage + האפליקציה זקוקה לאישורך כדי לפעול ברקע + פרטיות מצומצמת + רגיל + התעלם מאופטימיזציה + אם משתמש משאיר מכשיר מחובר לחשמל ויציב לתקופה מסוימת, כשהמסך כבוי, המכשיר עובר למצב Doze. זה מונע מאפליקציות גישה לרשת ומגדיר את העבודות, הסנכרונים וההתראות הסטנדרטיות שלהם. + אלמנט אינו מושפע מתהליך מיטוב הסוללה. + אופטימיזציה של הסוללה + השבת הגבלות + מגבלות רקע מופעלות עבור Element. +\nהעבודה שהאפליקציה מנסה לעשות תוגבל באגרסיביות בזמן שהיא ברקע, וזה עלול להשפיע על ההודעות. +\n% 1 $ s + מגבלות רקע מושבתות עבור Element. יש להריץ בדיקה זו באמצעות נתונים ניידים (ללא WIFI). +\n% 1 $ s + בדוק מגבלות רקע + הפעל את התחלה לאחר אתחול + השירות לא יופעל עם הפעלת המכשיר מחדש, לא תקבל התראות עד שאלמנט ייפתח לפחות פעם אחת. + השירות יתחיל עם הפעלת המכשיר מחדש. + הפעל לאחר אתחול + השירות נכשל מלעלות מחדש + השירות נסגר והופעל מחדש אוטומטית. + הפעלה מחדש אוטומטית לשירות ההתראות + החל שירות + שירות ההתראות אינו פועל. +\nנסה להפעיל מחדש את היישום. + שירות ההתראות פועל. + שירות התראות + ההודעה נלחצה! + אנא לחץ על ההודעה. אם אינך רואה את ההודעה, אנא בדוק את הגדרות המערכת. + תצוגת התראות + אתה צופה בהודעה! לחץ עלי! + קבלת הדחיפה נכשלה. הפתרון יכול להיות התקנה מחדש של היישום. + בדיקת שליחה בדחיפה (PUSH) + היישום מקבל PUSH + היישום ממתין ל- PUSH + נכשל רישום אסימון FCM ל- HomeServer: +\n% 1 $ s + אסימון FCM נרשם בהצלחה ל- HomeServer. + רישום אסימונים + הוסף חשבון + [% 1 $ s] +\nשגיאה זו אינה בשליטה על אלמנט. אין חשבון Google בטלפון. אנא פתח את מנהל החשבון והוסף חשבון Google. + [% 1 $ s] +\nשגיאה זו אינה בשליטה על אלמנט. זה יכול להתרחש מכמה סיבות. אולי זה יעבוד אם תנסה שוב מאוחר יותר, תוכל גם לבדוק ששירות Google Play אינו מוגבל בשימוש נתונים בהגדרות המערכת, או ששעון המכשיר שלך תקין, או שזה יכול לקרות ב- ROM מותאם אישית. + [% 1 $ s] +\nשגיאה זו איננה בשליטה על Element ולפי גוגל, שגיאה זו מצביעה על כך שלמכשיר יש יותר מדי אפליקציות הרשומות ב- FCM. השגיאה מתרחשת רק במקרים שבהם ישנם מספרים קיצוניים של אפליקציות, כך שהיא לא אמורה להשפיע על המשתמש הממוצע. + נכשל באחזור אסימון FCM: +\n% 1 $ s + אסימון FCM אוחזר בהצלחה: +\n% 1 $ s + אסימון Firebase + תקן שירותי Google Play + אלמנט משתמש בשירותי Google Play כדי להעביר הודעות פוש אך נראה שהוא אינו מוגדר כהלכה: +\n% 1 $ s + ה- APK של שירותי Google Play זמין ומעודכן. + בדיקת שירותי הפעלה + בדוק בהגדרות + טעינת הכללים המותאמים אישית נכשלה, אנא נסה שוב. + חדרים + אין תוצאות + סנן משתמשים מודרים + סנן חברים מהחדר + חפש + בטל הורדה + בטל העלאה + האם ברצונך להסתיר את כל ההודעות ממשתמש זה\? +\nשים לב שפעולה זו תפעיל מחדש את האפליקציה והיא עשויה להימשך זמן מה. + סיבה לדיווח על תוכן זה + הצטרף + מוזמן + תעודת זהות שגויה. צריכה להיות כתובת דוא\"ל או מזהה מטריצה כמו \'@localpart: domain\' + + % d נבחר + % d נבחרים + % d נבחרים + % d נבחרים + + הגדרות + קבצים + אנשים + פרטי החדר + קבל את האישור רק אם מנהל השרת פרסם טביעת אצבע התואמת את זו שלמעלה. + האישור השתנה מאישור מהימן בעבר לאיש מהימן. ייתכן שהשרת חידש את האישור שלו. פנה למנהל השרת לקבלת טביעת האצבע הצפויה. + האישור השתנה מאישור שהטלפון שלך אמין עליו. זה מאוד לא שגרתי. מומלץ לא לקבל את האישור החדש הזה. + אם מנהל השרת אמר שזה צפוי, ודא שטביעת האצבע שלמטה תואמת את טביעת האצבע שמספקת אותם. + יכול להיות שמישהו מיירט את התעבורה שלך בזדון, או שהטלפון שלך לא סומך על האישור שמספק השרת המרוחק. + לא ניתן לאמת את זהות השרת המרוחק. + טביעת אצבע (s%): + התעלם + יציאה + אל תתן אמון + אמון + + הודעה חדשה + הודעות חדשות + הודעות חדשות + הודעות חדשות + + אין לך הרשאה לפרסם בחדר זה + הקובץ לא נמצא + מחק הודעות שלא נשלחו + שלח שוב הודעות שלא נשלחו + שלח תשובה מוצפנת … + שלח הודעה (לא מוצפן) … + שלח הודעה מוצפנת … + % 1 $ s &% 2 $ s ואחרים מקלידים … + % 1 $ s &% 2 $ s מקלידים … + % s מקליד … + חפש + אימייל או מזהה מטריקס + אנא הזן כתובת דוא\"ל אחת או יותר או מזהה מטריקס + הזמן משתמש לפי מזהה + משתמשי מטריקס בלבד + תיקיית משתמש (s%) + אנשי קשר מקומיים (% d) + <u> הזמן לפי מזהה </ u>Invite by ID + %1$s %2$s + %1$s and %2$s + "%1$s, " + האם אתה בטוח שברצונך להזמין את% s לצ\'אט זה\? + סיבה + הסרת נידוי ממשתמש יאפשר לו להצטרף שוב לחדר. + איסור על המשתמש יבעט בהם מחדר זה וימנע מהם להצטרף שוב. + הסר נידוי ממשתמש + סיבות לנידוי + נדה משתמש + משתמש מעיף יסיר אותם מחדר זה. +\n +\nכדי למנוע מהם להצטרף שוב, עליך לאסור אותם במקום זאת. + סיבות להעפה + העף משתמש + האם אתה בטוח שברצונך לבטל את ההזמנה עבור משתמש זה\? + בטל הזמנה + הסרת התעלמות + ביטול חתימת משתמש זה יציג את כל ההודעות מהם שוב. + הסרת התעלמות ממשתמש + התעלם + התעלמות ממשתמש זה תסיר את ההודעות שלו מחדרים שאתה משתף. +\n +\nאתה יכול להפוך פעולה זו בכל עת בהגדרות הכלליות. + התעלם ממשתמש + לְהוֹרִיד בְּדַרגָה + לא תוכל לבטל את השינוי הזה מכיוון שאתה מוריד את עצמך בדרגה, אם אתה המשתמש המיועד האחרון בחדר, אי אפשר יהיה להחזיר לו הרשאות. + להוריד את עצמך\? + לא תוכל לבטל את השינוי הזה מכיוון שאתה מקדם את המשתמש לאותה רמת כוח כמוך. +\nהאם אתה בטוח\? + הצג רשימת מושבים + אזכר + מזהה משתמש, שם או דוא\"ל + הפוך למנהל + הפוך למנחה + אפס למשתמש רגיל + העף + הסרת התעלמות + התעלם + הסר מחדר זה + עזוב חדר זה + בטל הזמנה + הזמן + מושבים + הודעות ישירות + שיחה + כלי אדמיניסטרציה + לפני% 1 $ s% 2 $ s + % 1 $ s עכשיו + זמין + אופליין + אונליין + צור + חלק מההתראות מושבתות בהגדרות המותאמות אישית שלך. + שים לב שחלק מסוגי ההודעות מוגדרים כשתיקים (יפיקו התראה ללא צליל). + הגדרות מותאמות אישית. + אפשר + התראות אינן מופעלות עבור הפעלה זו. +\nאנא בדוק את הגדרות האלמנט. + התראות מופעלות להפעלה זו. + הגדרות מושב. + אפשר + התראות מושבתות עבור חשבונך. +\nאנא בדוק את הגדרות החשבון. + התראות מופעלות עבור חשבונך. + הגדרות חשבון. + פתח את ההגדרות + התראות מושבתות בהגדרות המערכת. +\nאנא בדוק את הגדרות המערכת. + התראות מופעלות בהגדרות המערכת. + הגדרות מערכת. + בדיקה אחת או יותר נכשלו, אנא שלח דו\"ח שגיאה שיעזור לנו לחקור זאת. + בדיקה אחת או יותר נכשלו, נסה הצעה/ות אלו לתיקון. + אבחון בסיסי תקין. אם עדיין אינך מקבל התראות, אנא שלח דו\"ח שגיאה שיעזור לנו לחקור זאת. + פועל ... (% 1 $ d מתוך% 2 $ d) + הרץ מבדקים + אבחון לפתרון בעיות + פותר בעיות התראות + פרטיות הודעות + חשיבות ההודעה לפי אירוע + הגדרות התראה מתקדמות + וודא שלחצת על הקישור בהודעת הדוא\"ל ששלחנו אליך. + להסיר את% s\? + מספרי טלפון + לא הוספה כתובת דוא\"ל לחשבונך + כתובות דוא\"ל + נדרש אימות + אינך יכול לעשות זאת ממכשיר נייד + אשר את סיסמתך + הצג את פרטי היישום בהגדרות המערכת. + מידע על האפליקציה + הוסף מספר טלפון + לא הוסף מספר טלפון לחשבונך + מספר טלפון + הוסף כתובת דוא\"ל + כתובת דוא\"ל + שם תצוגה + תמונת פרופיל + מדיניות הפרטיות + זכויות יוצרים + התראות צד שלישי + תנאים והגבלות + גרסה s% + גרסה + הגדרות + הודעות + הוסף למסך הבית + שכח + עזוב את השיחה + צ\'אט ישיר + בטל עדיפות + מועדף + השתק + אזכורים בלבד + כל ההודעות + כל ההודעות (קוליות) + מחפש בתיקייה… + + נמצא% 1 $ s חדר עבור% 2 $ s + נמצא% 1 $ s חדר עבור% 2 $ s + נמצא% 1 $ s חדר עבור% 2 $ s + נמצא% 1 $ s חדר עבור% 2 $ s + + + d% חדר + d% חדרים + d% חדרים + d% חדרים + + חפש בתיקיות + הקלד מזהה חדר או כינוי לחדר + הצטרף לחדר + הצטרף לחדר + צור חדר + התחלת שיחת צ\'אט + הזמנות + עדיפות נמוכה + חדרים + מועדפים + תיקייה ראשית + הצטרף + עדיין אין תמיכה בחיפוש בחדרים מוצפנים. + קבצים + אנשים + הודעות + האם אתה בטוח שברצונך להסיר את% s מהצ\'אט הזה\? + האם ברצונך לעזוב את החדר\? + עזוב חדר + + %dd + %dd + %dd + %dd + + + %dh + %dh + %dh + %dh + + + %dm + %dm + %dm + %dm + + + %ds + %ds + %ds + %ds + + חבר אחד + + חבר + חברים + חברים + חברים + + + חבר פעיל + חברים פעילים + חברים פעילים + חברים פעילים + + הוסף חבר \ No newline at end of file From 7f433ac4a09a0a9febe4fadfa70667a4dc665159 Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Sat, 9 Jan 2021 18:21:23 +0000 Subject: [PATCH 194/224] Translated using Weblate (Hebrew) Currently translated at 50.4% (1018 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 445 ++++++++++++++++++++++ 1 file changed, 445 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index b37c8fd70b..6208895dc4 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -761,4 +761,449 @@ חברים פעילים הוסף חבר + התחל אימות + מושב לא מאומת מבקש מפתחות הצפנה. +\nשם מושב: %1$s +\nנראה לאחרונה: %2$s +\nאם לא נכנסת למפגש אחר, התעלם מבקשה זו. + ההפעלה \'%s\' לא מאומתת מבקשת מפתחות הצפנה. + מושב חדש מבקש מפתחות הצפנה. +\nשם מושב: %1$s +\nנראה לאחרונה: %2$s +\nאם לא נכנסת למפגש אחר, התעלם מבקשה זו. + הוספת מושב חדש \'%s\', המבקש מפתחות הצפנה. + כדי להמשיך עליך לקבל את תנאי השירות הזה. + אפשרות זו מחייבת יישום צד שלישי להקליט את ההודעות. + שלח הודעות קוליות + השתמש במקש הזנת המקלדת כדי לשלוח הודעה + הפעל את מצלמת המערכת במקום את מסך המצלמה המותאם אישית. + השתמש במצלמה מקומית + אין יישומונים פעילים + נהל אינטגרציות + הוסף אפליקציות מטריקס + לא הוגדר מנהל אינטגרציה. + פרמטר אינו חוקי. + פרמטר חובה חסר. + החדר %s אינו גלוי. + חסר זהות משתמש בבקשה. + חסר מספר זהות חדר בבקשה. + אין לך אישור לעשות זאת בחדר זה. + אתה לא בחדר הזה. + רמת הרשאה חייבת להיות חיובית שלמה. + שליחת הבקשה נכשלה. + לא ניתן ליצור יישומון. + קרא מדיה מוגנת DRM + השתמש במיקרופון + השתמש במצלמה + חסום הכל + אפשר + יישומון זה רוצה להשתמש במשאבים הבאים: + מצטערים, שיחות ועידה עם Jitsi אינן נתמכות במכשירים ישנים (מכשירים עם מערכת הפעלה אנדרואיד מתחת ל -5.0) + מזהה חדר + מזהה ישומון + ערכת הנושא שלכם + מזהה המשתמש שלך + כתובת האתר של הדמות שלך + שם התצוגה שלך + בטל גישה עבורי + פתח בדפדפן + טען יישומון מחדש + השימוש בו עשוי לשתף נתונים עם %s: + השימוש בו עשוי להגדיר קובצי cookie ולשתף נתונים עם %s: + ישומון זה התווסף על ידי: + טען ישומון + ישומון + ישומונים פעילים + צפה + + %d יישומון פעיל + %d ישומונים פעילים + %d ישומונים פעילים + %d ישומונים אחרים פעילים + + האם אתה בטוח שברצונך למחוק את היישומון מחדר זה\? + צור שיחות ועידה עם jitsi + יצירת היישומון נכשלה + אתה זקוק להרשאה כדי לנהל יישומונים בחדר זה + ענק + הכי גדול + גדול יותר + גדול + רגיל + קטן + זעיר + גודל גופן + חפש היסטורי + %1$s: %2$s %3$s + %1$s:%2$s + ** השליחה נכשלה - אנא פתח את החדר + אני + הזמנות חדשות + הודעות חדשות + חדר + מאורע חדש + %1$s ו %2$s + %1$s ב %2$s ו %3$s + %1$s ב %2$s + + התראה %1$s: %2$d + התראות %1$s: %2$d + התראות מועטות %1$s: %2$d + התראות אחרות %1$s: %2$d + + + הודעה %1$s: %2$d + הודעות %1$s: %2$d + הודעות מעטות %1$s: %2$d + הודעות אחרות %1$s: %2$d + + + %d הזמנה + %d הזמנות + %d הזמנות מעטות + %d הזמנות אחרות + + + %d חדר + %d חדרים + %d חדרים מועטים + %d חדרים אחרים + + + %d הודעת התראה שלא נקראה + %d הודעות התראה שלא נקראו + %d הודעות התראה מעטות שלא נקראו + %d הודעות התראה אחרות שלא נקראו + + + הודעת התראה %d שלא נקראה + %d הודעות התראה שלא נקראו + %d הודעות התראה מעטות שלא נקראו + %d הודעות התראה אחרות שלא נקראו + + הקלד פה… + כל החדרים המקומיים %s + כל החדרים בשרת %s + כתובת אתר של שרת בית + הקלד שרת בית כדי לרשום ממנו חדרים ציבוריים + ייתכן שהשרת אינו זמין או עומס יתר + בחר מדריך חדרים + חדר זה מכיל פעילויות לא ידועות שלא אומתו. +\nהמשמעות היא שאין ערובה לכך שההפעלות שייכות למשתמשים שהם טוענים להם. +\nאנו ממליצים שתעבור את תהליך האימות של כל מפגש לפני שתמשיך, אך תוכל לשלוח שוב את ההודעה מבלי לאמת אם אתה מעדיף. +\n +\nהפעלות לא ידועות: + החדר מכיל הפעלות לא ידועות + אני מאשר שהמפתחות תואמים + אם הם לא תואמים, אבטחת התקשורת שלך עלולה להיפגע. + אשרו על ידי השוואה בין הדברים הבאים להגדרות המשתמש בפגישה האחרת שלכם: + אמת מושב + הסר מרשימה שחורה + רשימה שחורה + הסר אימות + אמת + ללא + IP לא ידוע + מושב לא ידוע + ברשימה שחורה + מאומת + לא תקין + + מפתח %1$d/%2$d מיובא בהצלחה. + מפתחות %1$d/%2$d יובאו בהצלחה. + מפתחות %1$d/%2$d מעטים יובאו בהצלחה. + מפתחות %1$d/%2$d אחרים יובאו בהצלחה. + + לעולם אל תשלח הודעות מוצפנות להפעלות לא מאומתות מהפגישה זו. + הצפן למפגשים מאומתים בלבד + יבא + ייבא את המפתחות מקובץ מקומי + ייבא מפתחות לחדר + ייבא מפתחות לחדר E2E + נהל גיבוי מפתח + שחזור הודעות מוצפנות + מפתחות יוצאו בהצלחה + מקשי החדר E2E נשמרו ב- \'%s\'. +\n +\nאזהרה: קובץ זה עשוי להימחק אם הסרת ההתקנה של היישום. + אנא צור משפט סיסמה להצפנת המפתחות המיוצאים. יהיה עליך להזין את אותו ביטוי סיסמה כדי שתוכל לייבא את המפתחות. + יצא + יצא מפתחות לקובץ מקומי + יצא מפתחות חדר + ייצא מפתחות חדר E2E + טביעת אצבע Ed25519 + אימות + מזהה מפתח + מזהה מושב + שם ציבורי + השם הציבורי של הפגישה גלוי לאנשים שאיתם אתה מתקשר + שם ציבורי (גלוי לאנשים שאיתם אתה מתקשר) + שם ציבורי + מידע על מושב השולח + שגיאת פענוח + מזהה מושב + מזהה משתמש + אַלגוֹרִיתְם + תביעת מפתח טביעת אצבע של Ed25519 + מפתח זהות Curve25519 + מידע על האירוע + מידע על הצפנה מקצה לקצה + %s ניסתה לטעון נקודה מסוימת בציר הזמן של החדר הזה אך לא הצליחה למצוא אותה. + ערכת נושא + מַדרִיך + אפשר הצפנה +\n(אזהרה: לא ניתן להשבית שוב!) + הצפנה מושבתת בחדר זה. + הצפנה מופעלת בחדר זה. + העתק כתובת חדר + העתק מזהה חדר + ביטול ההגדרה ככתובת הראשית + הגדר ככתובת ראשית + אזהרות כתובת עיקריות + לא תהיה לך כתובת ראשית שצוינה לחדר זה. + \'%s\' אינו פורמט חוקי לכינוי + פורמט כינוי לא חוקי + \'%s\' אינו מזהה קהילה חוקי + מזהה קהילה לא חוקי + מזהה קהילה חדש (למשל + foo: matrix.org) + חדר זה אינו מגלה כישרון בקרב קהילות כלשהן + כתובת חדשה (למשל #foo: matrix.org) + לחדר זה אין כתובות מקומיות + לעולם אל תשלח הודעות מוצפנות להפעלות לא מאומתות בחדר זה מהפגישה זו. + הצפן לביקורים מאומתים בלבד + עליך להתנתק כדי שתוכל לאפשר את ההצפנה. + הצפנה מקצה לקצה פעילה + הצפנה מקצה לקצה + אלה תכונות ניסיוניות שעשויות להישבר בדרכים לא צפויות. השתמש בזהירות. + מעבדות + כתובות + תעודת הזהות הפנימית של החדר הזה + מתקדם + משתמשים אסורים + כל מי שמכיר את הקישור לחדר, כולל אורחים + כל מי שמכיר את הקישור לחדר, מלבד האורחים + רק אנשים שהוזמנו + כדי לקשר לחדר חייבת להיות כתובת. + חברים בלבד (מאז שהצטרפו) + חברים בלבד (מאז שהוזמנו) + חברים בלבד (מאז נקודת הזמן לבחירת אפשרות זו) + כל אדם + לא ניתן לאחזר את הראות הנוכחית של ספריית החדרים (%1$s). + לפרסם את החדר הזה לציבור במדריך החדרים של %1$s\? + בטל את הפרסום של כתובת זו + פרסם כתובת זו + הוסף כתובת מקומית + לחדר זה אין כתובות מקומיות + הגדר כתובות לחדר זה כדי שמשתמשים יוכלו למצוא את החדר הזה דרך שרת הבית שלך (%1$s) + כתובות מקומיות + כתובת שפורסמה חדשה (למשל alias:server#) + עדיין אין כתובות שפורסמו. + עדיין אין כתובות שפורסמו, הוסף כתובת למטה. + פרסם חדר זה כציבורי ברשימת החדרים של \"%1$s\"\? + מחק את הכתובת \"%1$s\"\? + הסר פרסום של הכתובת \"%1$s\"\? + פרסם + פרסם כתובת חדשה באופן ידני + כתובות אחרות שפורסמו: + כתובת ראשית + זו הכתובת העיקרית + כל אחד מכל שרת יכול להשתמש בכתובות שפורסמו כדי להצטרף לחדר שלך. כדי לפרסם כתובת, תחילה יש להגדיר אותה ככתובת מקומית. + כתובות שפורסמו + כתובות חדרים + ראה וניהול כתובות של חדר זה, והנראות שלו בספריית החדרים. + כתובות החדר + גישה לחדר + מי יכול לגשת לחדר הזה\? + שינויים במי שיכול לקרוא היסטוריה יחולו רק על הודעות עתידיות בחדר זה. נראות ההיסטוריה הקיימת לא תשתנה. + מי יכול לקרוא היסטוריה\? + הקריאה בהיסטוריה של החדרים + גישה לחדר + התראות + רשום חדר זה ברשימת החדרים + כניסה ונראות + ללא + עדיפות נמוכה + מועדפים + תוייג כ-: + תגית חדר + נושא + שם חדר + תמונת חדר + לעד + חודש 1 + שבוע 1 + 3 ימים + אינכם חברים בשום קהילה. + כשרון + השמע צליל תריס + בחרו + מקור מדיה ברירת מחדל + בחרו + דחיסת ברירת מחדל + מדיה + מידע נוסף: %s + אירעה שגיאה במהלך אימות מספר הטלפון שלך. + קוד + שגיאה בעת אימות מספר הטלפון שלך + הזן קוד הפעלה + שלחנו SMS עם קוד הפעלה. אנא הזן קוד זה למטה. + אימות טלפון + מספר טלפון לא חוקי עבור המדינה שנבחרה + מספר טלפון + בבקשה בחרו מדינה + מדינה + בחר\\י מדינה + האם אתה בטוח שברצונך להסיר את %1$s %2$s \? + האם אתה בטוח שברצונך להסיר את יעד ההודעות הזה\? + נהל מיילים ומספרי טלפון המקושרים לחשבון מטריקס שלך + דוא\"ל ומספר טלפון + סיסמאות לא תואמות + הצג את כל ההודעות מ- %s\? +\n +\nשים לב שפעולה זו תפעיל מחדש את האפליקציה והיא עשויה להימשך זמן מה. + הסיסמה שלכם עודכנה + הסיסמה אינה תקינה + עדכון הסיסמה נכשל + עדכון סיסמה + אישור סיסמה חדשה + סיסמה חדשה + סיסמה נוכחית + שינוי סיסמה + סיסמה + הסתיים + שמור על מפתח התאוששות שלך במקום כלשהו מאובטח מאוד, כמו מנהל סיסמאות (או כספת) + מפתח השחזור שלך הוא רשת ביטחון - אתה יכול להשתמש בו כדי להחזיר את הגישה להודעות המוצפנות שלך אם תשכח את משפט הסיסמה שלך. +\nשמור על מפתח התאוששות שלך במקום כלשהו מאובטח מאוד, כמו מנהל סיסמאות (או כספת) + המפתחות שלך מגובים. + הצלחה! + (מתקדם) הגדר עם מפתח השחזור + לחלופין, אבטח את הגיבוי שלך באמצעות מפתח שחזור ושמור אותו במקום בטוח. + יוצר גיבוי + הגדר ביטוי + אנו נאחסן עותק מוצפן של המפתחות שלך בשרת הבית שלך. הגן על הגיבוי שלך באמצעות משפט סיסמה כדי לשמור על אבטחתו. +\n +\nליתר ביטחון, זה צריך להיות שונה מסיסמת החשבון שלך. + אבטח את הגיבוי שלך באמצעות משפט סיסמה. + ייצא ידנית מפתחות + (מתקדם) + התחל להשתמש בגיבוי מקשים + הודעות בחדרים מוצפנים מאובטחות באמצעות הצפנה מקצה לקצה. רק אתה והנמען / ים יש את המקשים לקריאת ההודעות האלה. +\n +\nגבה את המפתחות שלך בצורה מאובטחת כדי לא לאבד אותם. + לעולם אל תאבד הודעות מוצפנות + אין מושב מטריקס זמין + אנא מחק את משפט הסיסמה אם ברצונך ש- Element ייצור מפתח שחזור. + משפט הסיסמה חלש מדי + אנא הזן משפט סיסמה + משפט הסיסמה אינו תואם + הזן ביטוי סיסמה + אשר את ביטוי הסיסמה + צור ביטוי סיסמה + לא נמצא APK חוקי של שירותי Google Play. ייתכן שההודעות לא יפעלו כראוי. + %d+ + +%d + %1$s: %2$s + %1$s: + רק עבור שגיאות + עבור הודעות ושגיאות + לעולם + הראה את אזור המידע + כווץ + הרחב + סליחה, שגיאה התרחשה + שרת הבית שלך עדיין לא תומך בטעינה עצלה של חברי החדר. נסה מאוחר יותר. + הגדל את הביצועים רק על ידי חברי חדר העמסה בתצוגה הראשונה. + טעינה עצלה של חברים וחדרים + אנא %s להמשיך להשתמש בשירות זה. + אנא %s כדי להגדיל מגבלה זו. + שרת בית זה הגיע למגבלת המשתמשים הפעילים החודשיים שלו. + שרת בית זה הגיע למגבלת המשתמשים הפעילים החודשיים כך ש חלק מהמשתמשים לא יוכלו להתחבר . + שרת בית זה חרג מאחד ממגבלות המשאבים שלו. + שרת בית זה חרג מאחד ממגבלות המשאבים שלו כך ש משתמשים מסוימים לא יוכלו להתחבר . + פנה למנהל השירות שלך + צור קשר עם מנהל המערכת + לחץ כאן כדי לראות הודעות ישנות יותר ממגבלת המשאבים + לחץ כאן לצפייה בהודעות ישנות יותר + החדר הזה הוא המשך לשיחה אחרת + השיחה נמשכת כאן + חדר זה הוחלף ואינו פעיל יותר + אנא הזינו את סיסמה שלכם. + אהא הזינו שם משתמש. + השבת חשבון + להמשך, הזן את הסיסמה שלך: + אנא שכח את כל ההודעות ששלחתי כאשר חשבוני מושבת (אזהרה: הדבר יגרום למשתמשים עתידיים לראות תצוגה חלקית של השיחות) + זה יהפוך את חשבונך ללא שימוש לצמיתות. לא תוכל להתחבר, ואף אחד לא יוכל לרשום מחדש את אותו מזהה משתמש. הדבר יביא לחשבונך לעזוב את כל החדרים בהם הוא משתתף, והוא יסיר את פרטי חשבונך משרת הזהות שלך. פעולה זו היא בלתי הפיכה . +\n +\nהשבתת חשבונך אינה גורמת לנו כברירת מחדל לשכוח הודעות ששלחת . אם תרצה שנשכח את ההודעות שלך, סמן את התיבה למטה. +\n +\nנראות ההודעות במטריקס דומה לדוא\"ל. המשמעות של שכחת ההודעות שלך היא שהודעות ששלחת לא ישותפו עם משתמשים חדשים או לא רשומים, אך למשתמשים רשומים שכבר יש גישה להודעות אלה עדיין תהיה גישה להעתק שלהם. + השבת חשבון + בדוק כעת + כדי להמשיך להשתמש בשרת הבית %1$s עליך לבדוק ולהסכים לתנאים ולהגבלות. + אווטאר + אוואטר התרעה + אווטאר קבלה + שכח חדר + לָשׁוּב וֵלְהִצְטַרֵף + סיבה: %1$s + חסום על ידי %2$s מ- %1$s + אתה נבעט מ- %1$s על ידי %2$s + מנהל הקהילה לא סיפק תיאור ארוך לקהילה זו. + + חדר %d + %d חדרים + %d חדרים + %d חדרים אחרים + + + חבר %d + %d חברים + %d חברים + %d חברים אחרים + + סנן קבוצות חדרים + סנן חברי קבוצה + הוזמנו + הצתרפו + חדרים + אין משתמשים + חדרים + אנשים + בית + דוגמא + מזהה קהילה + דוגמא + שם הקהילה + צור קהילה + צור + הודעה מוצפנת + רועש + שקט + כבוי + סימון ההפעלה הושבת. + סימון ההפעלה הופעל. + כדי לתקן את ניהול אפליקציות מטריקס + הפעלה / כיבוי של סימון MARKDOWN + משנה את כינוי התצוגה שלך + בועט משתמש עם מזהה נתון + הגדר את נושא החדר + עזוב חדר + מצטרף לחדר עם כינוי נתון + מזמין משתמש עם זיהוי נתון לחדר הנוכחי + משתמש מבוטל עם מזהה נתון + הגדר את רמת ההרשאה של המשתמש + הסר חסימה למשתמש עם מזהה נתון + חסום משתמש עם מזהה נתון + הצג פעולה + הפקודה \"%s\" זקוקה ליותר פרמטרים, או שחלק מהפרמטרים שגויים. + פקודה לא מוכרת: %s + שגיאת פקודה + שיחת ועידה נמצאת בפיתוח ואולי לא אמינה. + אזהרה! + התעלם + התעלם מהבקשה + בקשה לשיתוף מפתח + שיתוף + שתף ללא אימות + אמת \ No newline at end of file From cf1628228aed547b402306462d6d2f5c245ce27b Mon Sep 17 00:00:00 2001 From: Ahrale Date: Fri, 8 Jan 2021 14:36:53 +0000 Subject: [PATCH 195/224] Translated using Weblate (Hebrew) Currently translated at 50.4% (1018 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 6208895dc4..143a156916 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -375,8 +375,8 @@ קטן בינוני גדול - מקורי - שלח כ: + מקור + שלח כ שינוי בפרט חברות שינוי בפרטי חברות From 793c0ababbcc61ee65101b411232c2fdaa7027a4 Mon Sep 17 00:00:00 2001 From: gkkulik Date: Sat, 9 Jan 2021 16:31:21 +0000 Subject: [PATCH 196/224] Translated using Weblate (Silesian) Currently translated at 3.1% (63 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/szl/ --- vector/src/main/res/values-szl/strings.xml | 66 +++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-szl/strings.xml b/vector/src/main/res/values-szl/strings.xml index a6b3daec93..41a3680054 100644 --- a/vector/src/main/res/values-szl/strings.xml +++ b/vector/src/main/res/values-szl/strings.xml @@ -1,2 +1,66 @@ - \ No newline at end of file + + Zawrzij + Strzim + Ôdtwōrz + Aktywne połōnczynie + Zgłoś zawartość + Rozłōncz + Ôdkoż + Brak + Przemianuj + Skasuj + Pokoż ôdszyfrowane zdrzōdło + Pokoż zdrzōdło + Bezpostrzedni link + Przekoż + Niyskorzij + Wymaż + Godej + Udostympnij + Pobier + Cytuj + Wymaż + Wyślij zaś + Wyślij + Ôstōń + Pociep + Spamiyntej + Pociep + OK + Wgrowanie… + Licyncyje podmiotōw trzecich + Stracisz dostymp do zaszyfrowanych wiadōmości, chyba że wykōnosz ibryczno kopijo kluczy przed ôdlogowaniym sie. + Stwōrz kopijo ibryczno + Je żeś zicher\? + Użyj ibrycznyj kopije klucza + Tworzynie ibrycznyj kopije kluczy… + Niy chca mojich zaszyfrowanych wiadōmości + Coby niy stracić dostympu do swojich zaszyfrowanych wiadōmości, aktywuj ibryczno kopijo klucza na wszyskich aktywnych sesyjach. + Trwo tworzynie ibrycznyj kopije klucza. Jeźli ôdlogujesz sie teroz, to stracisz dostymp do zaszyfrowanych wiadōmości. + Stracisz zaszyfrowane wiadōmości, jeźli sie teroz ôdlogujesz + Ibryczno kopijo kluczy niy ma gotowo, prosza czekać… + Zweryfikuj sesyjo + Użyj ibrycznyj kopije klucza + Ibryczno Kopijo Klucza + Wyślij nalepka + Informacyje ô społeczności + Zgłoś feler + Archiwum + Informacyje ô używoczu + Sztalōnki + Izba + Wiadōmości + Ciche powiadōmiynia + Głośne powiadōmiynia + Nasuchowanie zdarzyń + Synchrōnizowanie… + Inicjalizacyjo usugi + Tymat Status.im + Czorny tymat + Ciymny tymat + Jasny tymat + Latn + PL + pl + \ No newline at end of file From 26c4c7e467456bfd426e3bf6896bcaca841763d9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 11 Jan 2021 17:10:08 +0100 Subject: [PATCH 197/224] split long line --- .../home/room/detail/timeline/item/MessageImageVideoItem.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index 5d14178088..b121b14b4a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -56,7 +56,11 @@ abstract class MessageImageVideoItem : AbsMessageItem Date: Tue, 12 Jan 2021 09:14:30 +0100 Subject: [PATCH 198/224] Code review --- .../sdk/internal/crypto/MXOlmDevice.kt | 44 +++++++++---------- .../megolm/MXOutboundSessionInfo.kt | 1 + .../crypto/store/db/RealmCryptoStore.kt | 22 +++++----- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt index a892d3850a..71c1cfc728 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt @@ -66,10 +66,9 @@ internal class MXOlmDevice @Inject constructor( private var olmUtility: OlmUtility? = null // The outbound group session. - // They are not stored in 'store' to avoid to remember to which devices we sent the session key. - // Plus, in cryptography, it is good to refresh sessions from time to time. + // Caches active outbound session to avoid to sync with DB before read // The key is the session id, the value the outbound group session. - private val outboundGroupSessionStore: MutableMap = HashMap() + private val outboundGroupSessionCache: MutableMap = HashMap() // Store a set of decrypted message indexes for each group session. // This partially mitigates a replay attack where a MITM resends a group @@ -137,10 +136,10 @@ internal class MXOlmDevice @Inject constructor( */ fun release() { olmUtility?.releaseUtility() - outboundGroupSessionStore.values.forEach { + outboundGroupSessionCache.values.forEach { it.releaseSession() } - outboundGroupSessionStore.clear() + outboundGroupSessionCache.clear() } /** @@ -416,7 +415,7 @@ internal class MXOlmDevice @Inject constructor( var session: OlmOutboundGroupSession? = null try { session = OlmOutboundGroupSession() - outboundGroupSessionStore[session.sessionIdentifier()] = session + outboundGroupSessionCache[session.sessionIdentifier()] = session store.storeCurrentOutboundGroupSessionForRoom(roomId, session) return session.sessionIdentifier() } catch (e: Exception) { @@ -429,33 +428,34 @@ internal class MXOlmDevice @Inject constructor( } fun storeOutboundGroupSessionForRoom(roomId: String, sessionId: String) { - outboundGroupSessionStore[sessionId]?.let { + outboundGroupSessionCache[sessionId]?.let { store.storeCurrentOutboundGroupSessionForRoom(roomId, it) } } - fun restoreOutboundGroupSessionForRoom(roomId: String): MXOutboundSessionInfo? { + fun restoreOutboundGroupSessionForRoom(roomId: String): MXOutboundSessionInfo? { val restoredOutboundGroupSession = store.getCurrentOutboundGroupSessionForRoom(roomId) if (restoredOutboundGroupSession != null) { val sessionId = restoredOutboundGroupSession.outboundGroupSession.sessionIdentifier() - if (!outboundGroupSessionStore.containsKey(sessionId)) { - outboundGroupSessionStore[sessionId] = restoredOutboundGroupSession.outboundGroupSession - return MXOutboundSessionInfo( - sessionId = sessionId, - sharedWithHelper = SharedWithHelper(roomId, sessionId, store), - restoredOutboundGroupSession.creationTime - ) - } else { - restoredOutboundGroupSession.outboundGroupSession.releaseSession() - } + // cache it + outboundGroupSessionCache[sessionId] = restoredOutboundGroupSession.outboundGroupSession + + return MXOutboundSessionInfo( + sessionId = sessionId, + sharedWithHelper = SharedWithHelper(roomId, sessionId, store), + restoredOutboundGroupSession.creationTime + ) } return null } fun discardOutboundGroupSessionForRoom(roomId: String) { - outboundGroupSessionStore.remove(roomId)?.releaseSession() + store.getCurrentOutboundGroupSessionForRoom(roomId)?.outboundGroupSession?.sessionIdentifier()?.let { sessionId -> + outboundGroupSessionCache.remove(sessionId)?.releaseSession() + } store.storeCurrentOutboundGroupSessionForRoom(roomId, null) } + /** * Get the current session key of an outbound group session. * @@ -465,7 +465,7 @@ internal class MXOlmDevice @Inject constructor( fun getSessionKey(sessionId: String): String? { if (sessionId.isNotEmpty()) { try { - return outboundGroupSessionStore[sessionId]!!.sessionKey() + return outboundGroupSessionCache[sessionId]!!.sessionKey() } catch (e: Exception) { Timber.e(e, "## getSessionKey() : failed") } @@ -481,7 +481,7 @@ internal class MXOlmDevice @Inject constructor( */ fun getMessageIndex(sessionId: String): Int { return if (sessionId.isNotEmpty()) { - outboundGroupSessionStore[sessionId]!!.messageIndex() + outboundGroupSessionCache[sessionId]!!.messageIndex() } else 0 } @@ -495,7 +495,7 @@ internal class MXOlmDevice @Inject constructor( fun encryptGroupMessage(sessionId: String, payloadString: String): String? { if (sessionId.isNotEmpty() && payloadString.isNotEmpty()) { try { - return outboundGroupSessionStore[sessionId]!!.encryptMessage(payloadString) + return outboundGroupSessionCache[sessionId]!!.encryptMessage(payloadString) } catch (e: Exception) { Timber.e(e, "## encryptGroupMessage() : failed") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt index c0b920b09d..5a68937868 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt @@ -24,6 +24,7 @@ internal class MXOutboundSessionInfo( // The id of the session val sessionId: String, val sharedWithHelper: SharedWithHelper, + // When the session was created private val creationTime: Long = System.currentTimeMillis()) { // Number of times this session has been used diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 7912d03ffd..369a4976c9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -780,20 +780,18 @@ internal class RealmCryptoStore @Inject constructor( // this is called for each sent message (so not high frequency), thus we can use basic realm async without // risk of reaching max async operation limit? doRealmTransactionAsync(realmConfiguration) { realm -> - realm.where() - .equalTo(CryptoRoomEntityFields.ROOM_ID, roomId) - .findFirst()?.let { entity -> - // we should delete existing outbound session info if any - entity.outboundSessionInfo?.deleteFromRealm() + CryptoRoomEntity.getById(realm, roomId)?.let { entity -> + // we should delete existing outbound session info if any + entity.outboundSessionInfo?.deleteFromRealm() - if (outboundGroupSession != null) { - val info = realm.createObject(OutboundGroupSessionInfoEntity::class.java).apply { - creationTime = System.currentTimeMillis() - putOutboundGroupSession(outboundGroupSession) - } - entity.outboundSessionInfo = info - } + if (outboundGroupSession != null) { + val info = realm.createObject(OutboundGroupSessionInfoEntity::class.java).apply { + creationTime = System.currentTimeMillis() + putOutboundGroupSession(outboundGroupSession) } + entity.outboundSessionInfo = info + } + } } } From 426782a001f70c0a32038cde1f270e9946194000 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 12 Jan 2021 09:48:02 +0100 Subject: [PATCH 199/224] remember groupId in session cache --- .../sdk/internal/crypto/MXOlmDevice.kt | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt index 71c1cfc728..b1e91e8d50 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt @@ -65,10 +65,15 @@ internal class MXOlmDevice @Inject constructor( // The OLM lib utility instance. private var olmUtility: OlmUtility? = null + private data class GroupSessionCacheItem( + val groupId: String, + val groupSession: OlmOutboundGroupSession + ) + // The outbound group session. // Caches active outbound session to avoid to sync with DB before read - // The key is the session id, the value the outbound group session. - private val outboundGroupSessionCache: MutableMap = HashMap() + // The key is the session id, the value the . + private val outboundGroupSessionCache: MutableMap = HashMap() // Store a set of decrypted message indexes for each group session. // This partially mitigates a replay attack where a MITM resends a group @@ -137,7 +142,7 @@ internal class MXOlmDevice @Inject constructor( fun release() { olmUtility?.releaseUtility() outboundGroupSessionCache.values.forEach { - it.releaseSession() + it.groupSession.releaseSession() } outboundGroupSessionCache.clear() } @@ -415,7 +420,7 @@ internal class MXOlmDevice @Inject constructor( var session: OlmOutboundGroupSession? = null try { session = OlmOutboundGroupSession() - outboundGroupSessionCache[session.sessionIdentifier()] = session + outboundGroupSessionCache[session.sessionIdentifier()] = GroupSessionCacheItem(roomId, session) store.storeCurrentOutboundGroupSessionForRoom(roomId, session) return session.sessionIdentifier() } catch (e: Exception) { @@ -429,7 +434,7 @@ internal class MXOlmDevice @Inject constructor( fun storeOutboundGroupSessionForRoom(roomId: String, sessionId: String) { outboundGroupSessionCache[sessionId]?.let { - store.storeCurrentOutboundGroupSessionForRoom(roomId, it) + store.storeCurrentOutboundGroupSessionForRoom(roomId, it.groupSession) } } @@ -438,7 +443,7 @@ internal class MXOlmDevice @Inject constructor( if (restoredOutboundGroupSession != null) { val sessionId = restoredOutboundGroupSession.outboundGroupSession.sessionIdentifier() // cache it - outboundGroupSessionCache[sessionId] = restoredOutboundGroupSession.outboundGroupSession + outboundGroupSessionCache[sessionId] = GroupSessionCacheItem(roomId, restoredOutboundGroupSession.outboundGroupSession) return MXOutboundSessionInfo( sessionId = sessionId, @@ -450,8 +455,12 @@ internal class MXOlmDevice @Inject constructor( } fun discardOutboundGroupSessionForRoom(roomId: String) { - store.getCurrentOutboundGroupSessionForRoom(roomId)?.outboundGroupSession?.sessionIdentifier()?.let { sessionId -> - outboundGroupSessionCache.remove(sessionId)?.releaseSession() + val toDiscard = outboundGroupSessionCache.filter { + it.value.groupId == roomId + } + toDiscard.forEach { (sessionId, cacheItem) -> + cacheItem.groupSession.releaseSession() + outboundGroupSessionCache.remove(sessionId) } store.storeCurrentOutboundGroupSessionForRoom(roomId, null) } @@ -465,7 +474,7 @@ internal class MXOlmDevice @Inject constructor( fun getSessionKey(sessionId: String): String? { if (sessionId.isNotEmpty()) { try { - return outboundGroupSessionCache[sessionId]!!.sessionKey() + return outboundGroupSessionCache[sessionId]!!.groupSession.sessionKey() } catch (e: Exception) { Timber.e(e, "## getSessionKey() : failed") } @@ -481,7 +490,7 @@ internal class MXOlmDevice @Inject constructor( */ fun getMessageIndex(sessionId: String): Int { return if (sessionId.isNotEmpty()) { - outboundGroupSessionCache[sessionId]!!.messageIndex() + outboundGroupSessionCache[sessionId]!!.groupSession.messageIndex() } else 0 } @@ -495,7 +504,7 @@ internal class MXOlmDevice @Inject constructor( fun encryptGroupMessage(sessionId: String, payloadString: String): String? { if (sessionId.isNotEmpty() && payloadString.isNotEmpty()) { try { - return outboundGroupSessionCache[sessionId]!!.encryptMessage(payloadString) + return outboundGroupSessionCache[sessionId]!!.groupSession.encryptMessage(payloadString) } catch (e: Exception) { Timber.e(e, "## encryptGroupMessage() : failed") } From 83072451202f78e6d90e967adaa127dc4118b250 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 11 Jan 2021 18:31:57 +0100 Subject: [PATCH 200/224] Fix issue with delay set to 0 --- .../sdk/internal/session/sync/job/SyncService.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index 9d854229df..16c4095654 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -166,15 +166,17 @@ abstract class SyncService : Service() { } if (throwable is Failure.NetworkConnection) { // Timeout is not critical, so retry as soon as possible. - val retryDelay = if (isInitialSync || throwable.cause is SocketTimeoutException) { - 0 - } else { - syncDelaySeconds + if (isInitialSync || throwable.cause is SocketTimeoutException) { + // For big accounts, computing init sync response can take time, but Synapse will cache the + // result for the next request. So keep retrying in loop + Timber.w("Timeout during initial sync, retry in loop") + doSync() + return } // Network might be off, no need to reschedule endless alarms :/ preventReschedule = true // Instead start a work to restart background sync when network is on - onNetworkError(sessionId ?: "", isInitialSync, syncTimeoutSeconds, retryDelay) + onNetworkError(sessionId ?: "", isInitialSync, syncTimeoutSeconds, syncDelaySeconds) } // JobCancellation could be caught here when onDestroy cancels the coroutine context if (isRunning.get()) stopMe() From ec0a04e89305004a1f321849b45c46224f7b4fe6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 10:45:18 +0100 Subject: [PATCH 201/224] timeout -> restart without delay --- .../android/sdk/internal/session/sync/job/SyncService.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index 16c4095654..a535a322f4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -166,10 +166,10 @@ abstract class SyncService : Service() { } if (throwable is Failure.NetworkConnection) { // Timeout is not critical, so retry as soon as possible. - if (isInitialSync || throwable.cause is SocketTimeoutException) { - // For big accounts, computing init sync response can take time, but Synapse will cache the + if (throwable.cause is SocketTimeoutException) { + // For big accounts, computing sync response can take time, but Synapse will cache the // result for the next request. So keep retrying in loop - Timber.w("Timeout during initial sync, retry in loop") + Timber.w("Timeout during sync, retry in loop") doSync() return } From b69d8ad71a400c8abe863b55445a94b06137082e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 11:13:38 +0100 Subject: [PATCH 202/224] Code cleanup, fix crash if `appContext !is HasVectorInjector` --- .../receiver/AlarmSyncBroadcastReceiver.kt | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt index 674e7dfef5..1b5c71d952 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt @@ -26,28 +26,20 @@ import androidx.core.content.ContextCompat import androidx.core.content.getSystemService import im.vector.app.core.di.HasVectorInjector import im.vector.app.core.services.VectorSyncService -import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.internal.session.sync.job.SyncService import timber.log.Timber class AlarmSyncBroadcastReceiver : BroadcastReceiver() { - lateinit var vectorPreferences: VectorPreferences - override fun onReceive(context: Context, intent: Intent) { - val appContext = context.applicationContext - if (appContext is HasVectorInjector) { - val activeSession = appContext.injector().activeSessionHolder().getSafeActiveSession() - if (activeSession == null) { - Timber.v("No active session don't launch sync service.") - return - } - vectorPreferences = appContext.injector().vectorPreferences() - } + Timber.d("## Sync: AlarmSyncBroadcastReceiver received intent") + val vectorPreferences = (context.applicationContext as? HasVectorInjector) + ?.injector() + ?.takeIf { it.activeSessionHolder().getSafeActiveSession() != null } + ?.vectorPreferences() + ?: return Unit.also { Timber.v("No active session, so don't launch sync service.") } val sessionId = intent.getStringExtra(SyncService.EXTRA_SESSION_ID) ?: return - // This method is called when the BroadcastReceiver is receiving an Intent broadcast. - Timber.d("RestartBroadcastReceiver received intent") VectorSyncService.newPeriodicIntent(context, sessionId, vectorPreferences.backgroundSyncTimeOut(), vectorPreferences.backgroundSyncDelay()).let { try { ContextCompat.startForegroundService(context, it) From 561b89830a842bda22cd0078d64e7355283cdce2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 11:21:22 +0100 Subject: [PATCH 203/224] Avoid default value for param --- .../im/vector/app/core/services/VectorSyncService.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 0950bdf121..36f7497b7d 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -89,11 +89,11 @@ class VectorSyncService : SyncService() { } override fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { - rescheduleSyncService(sessionId, timeout, delay) + rescheduleSyncService(sessionId, timeout, delay, false) } override fun onNetworkError(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { - Timber.d("## Sync: A network error occured during sync") + Timber.d("## Sync: A network error occurred during sync") val rescheduleSyncWorkRequest: WorkRequest = OneTimeWorkRequestBuilder() .setInputData(Data.Builder() @@ -137,8 +137,11 @@ class VectorSyncService : SyncService() { } } -private fun Context.rescheduleSyncService(sessionId: String, timeout: Int, delay: Int, networkBack: Boolean = false) { - val periodicIntent = VectorSyncService.newPeriodicIntent(this, sessionId, timeout, delay, networkBack) +private fun Context.rescheduleSyncService(sessionId: String, + timeout: Int, + delay: Int, + isNetworkBack: Boolean) { + val periodicIntent = VectorSyncService.newPeriodicIntent(this, sessionId, timeout, delay, isNetworkBack) val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { PendingIntent.getForegroundService(this, 0, periodicIntent, 0) } else { From d46ae83dc49fcfbee07bc12790a50ecd53c32a05 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 11:41:20 +0100 Subject: [PATCH 204/224] Define constant for keys --- .../app/core/services/VectorSyncService.kt | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 36f7497b7d..ce1e8d136d 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -96,12 +96,7 @@ class VectorSyncService : SyncService() { Timber.d("## Sync: A network error occurred during sync") val rescheduleSyncWorkRequest: WorkRequest = OneTimeWorkRequestBuilder() - .setInputData(Data.Builder() - .putString("sessionId", sessionId) - .putInt("timeout", timeout) - .putInt("delay", delay) - .build() - ) + .setInputData(RestartWhenNetworkOn.createInputData(sessionId, timeout, delay)) .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() @@ -124,16 +119,32 @@ class VectorSyncService : SyncService() { notificationManager.cancel(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE) } + // I do not move or rename this class, since I'm not sure about the side effect regarding the WorkManager class RestartWhenNetworkOn(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { - val sessionId = inputData.getString("sessionId") ?: return Result.failure() - val timeout = inputData.getInt("timeout", 6) - val delay = inputData.getInt("delay", 60) + Timber.d("## Sync: RestartWhenNetworkOn.doWork()") + val sessionId = inputData.getString(KEY_SESSION_ID) ?: return Result.failure() + val timeout = inputData.getInt(KEY_TIMEOUT, 6) + val delay = inputData.getInt(KEY_DELAY, 60) applicationContext.rescheduleSyncService(sessionId, timeout, delay, true) // Indicate whether the work finished successfully with the Result return Result.success() } + + companion object { + fun createInputData(sessionId: String, timeout: Int, delay: Int): Data { + return Data.Builder() + .putString(KEY_SESSION_ID, sessionId) + .putInt(KEY_TIMEOUT, timeout) + .putInt(KEY_DELAY, delay) + .build() + } + + private const val KEY_SESSION_ID = "sessionId" + private const val KEY_TIMEOUT = "timeout" + private const val KEY_DELAY = "delay" + } } } From aac3f379a782a45aa3294e88b562367adbb95739 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 11:42:39 +0100 Subject: [PATCH 205/224] Add a log --- .../matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt index c6647f7572..b58cab99b5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.work.ListenableWorker import androidx.work.WorkerFactory import androidx.work.WorkerParameters +import timber.log.Timber import javax.inject.Inject import javax.inject.Provider @@ -32,6 +33,8 @@ class MatrixWorkerFactory @Inject constructor( workerClassName: String, workerParameters: WorkerParameters ): ListenableWorker? { + Timber.d("MatrixWorkerFactory.createWorker for $workerClassName") + val foundEntry = workerFactories.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) } val factoryProvider = foundEntry?.value From 609ceb7fa421b8d2189e5df9e83524a648c5d63a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 12:06:52 +0100 Subject: [PATCH 206/224] Avoid Magic numbers --- .../sdk/internal/session/sync/job/SyncService.kt | 13 +++++++++---- .../vector/app/core/services/VectorSyncService.kt | 10 ++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index a535a322f4..c79b25fb93 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -50,8 +50,9 @@ abstract class SyncService : Service() { private var sessionId: String? = null private var mIsSelfDestroyed: Boolean = false - private var syncTimeoutSeconds: Int = 6 - private var syncDelaySeconds: Int = 60 + private var syncTimeoutSeconds: Int = getDefaultSyncTimeoutSeconds() + private var syncDelaySeconds: Int = getDefaultSyncDelaySeconds() + private var periodic: Boolean = false private var preventReschedule: Boolean = false @@ -190,8 +191,8 @@ abstract class SyncService : Service() { } val matrix = Matrix.getInstance(applicationContext) val safeSessionId = intent.getStringExtra(EXTRA_SESSION_ID) ?: return false - syncTimeoutSeconds = intent.getIntExtra(EXTRA_TIMEOUT_SECONDS, 6) - syncDelaySeconds = intent.getIntExtra(EXTRA_DELAY_SECONDS, 60) + syncTimeoutSeconds = intent.getIntExtra(EXTRA_TIMEOUT_SECONDS, getDefaultSyncTimeoutSeconds()) + syncDelaySeconds = intent.getIntExtra(EXTRA_DELAY_SECONDS, getDefaultSyncDelaySeconds()) try { val sessionComponent = matrix.sessionManager.getSessionComponent(safeSessionId) ?: throw IllegalStateException("## Sync: You should have a session to make it work") @@ -210,6 +211,10 @@ abstract class SyncService : Service() { } } + abstract fun getDefaultSyncTimeoutSeconds(): Int + + abstract fun getDefaultSyncDelaySeconds(): Int + abstract fun onStart(isInitialSync: Boolean) abstract fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index ce1e8d136d..dbf51b3c99 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -33,6 +33,7 @@ import androidx.work.WorkerParameters import im.vector.app.R import im.vector.app.core.extensions.vectorComponent import im.vector.app.features.notifications.NotificationUtils +import im.vector.app.features.settings.BackgroundSyncMode import org.matrix.android.sdk.internal.session.sync.job.SyncService import timber.log.Timber @@ -78,6 +79,10 @@ class VectorSyncService : SyncService() { notificationUtils = vectorComponent().notificationUtils() } + override fun getDefaultSyncDelaySeconds() = BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS + + override fun getDefaultSyncTimeoutSeconds() = BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS + override fun onStart(isInitialSync: Boolean) { val notificationSubtitleRes = if (isInitialSync) { R.string.notification_initial_sync @@ -125,8 +130,8 @@ class VectorSyncService : SyncService() { override fun doWork(): Result { Timber.d("## Sync: RestartWhenNetworkOn.doWork()") val sessionId = inputData.getString(KEY_SESSION_ID) ?: return Result.failure() - val timeout = inputData.getInt(KEY_TIMEOUT, 6) - val delay = inputData.getInt(KEY_DELAY, 60) + val timeout = inputData.getInt(KEY_TIMEOUT, BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS) + val delay = inputData.getInt(KEY_DELAY, BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS) applicationContext.rescheduleSyncService(sessionId, timeout, delay, true) // Indicate whether the work finished successfully with the Result return Result.success() @@ -152,6 +157,7 @@ private fun Context.rescheduleSyncService(sessionId: String, timeout: Int, delay: Int, isNetworkBack: Boolean) { + Timber.d("## Sync: rescheduleSyncService") val periodicIntent = VectorSyncService.newPeriodicIntent(this, sessionId, timeout, delay, isNetworkBack) val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { PendingIntent.getForegroundService(this, 0, periodicIntent, 0) From b20bbc12957b5e70217a1be3a6d568f16945d5f2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 13:56:06 +0100 Subject: [PATCH 207/224] When network is back, do an immediate sync --- .../app/core/services/VectorSyncService.kt | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index dbf51b3c99..2f21d53177 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -159,16 +159,22 @@ private fun Context.rescheduleSyncService(sessionId: String, isNetworkBack: Boolean) { Timber.d("## Sync: rescheduleSyncService") val periodicIntent = VectorSyncService.newPeriodicIntent(this, sessionId, timeout, delay, isNetworkBack) - val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - PendingIntent.getForegroundService(this, 0, periodicIntent, 0) + + if (isNetworkBack || delay == 0) { + // Do not wait, do the sync now (more reactivity if network back is due to user action) + startService(periodicIntent) } else { - PendingIntent.getService(this, 0, periodicIntent, 0) - } - val firstMillis = System.currentTimeMillis() + delay * 1000L - val alarmMgr = getSystemService()!! - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) - } else { - alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) + val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + PendingIntent.getForegroundService(this, 0, periodicIntent, 0) + } else { + PendingIntent.getService(this, 0, periodicIntent, 0) + } + val firstMillis = System.currentTimeMillis() + delay * 1000L + val alarmMgr = getSystemService()!! + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) + } else { + alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) + } } } From e771b21ea3c0578dfd3cfc06e597d7b98953800a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 15:21:16 +0100 Subject: [PATCH 208/224] Rename parameters for clarity --- .../receiver/AlarmSyncBroadcastReceiver.kt | 25 +++++++----- .../im/vector/app/core/extensions/Session.kt | 21 ++++++---- .../app/core/services/VectorSyncService.kt | 40 +++++++++++-------- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt index 1b5c71d952..b94e99208b 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt @@ -40,15 +40,22 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() { ?: return Unit.also { Timber.v("No active session, so don't launch sync service.") } val sessionId = intent.getStringExtra(SyncService.EXTRA_SESSION_ID) ?: return - VectorSyncService.newPeriodicIntent(context, sessionId, vectorPreferences.backgroundSyncTimeOut(), vectorPreferences.backgroundSyncDelay()).let { - try { - ContextCompat.startForegroundService(context, it) - } catch (ex: Throwable) { - Timber.i("## Sync: Failed to start service, Alarm scheduled to restart service") - scheduleAlarm(context, sessionId, vectorPreferences.backgroundSyncDelay()) - Timber.e(ex) - } - } + VectorSyncService.newPeriodicIntent( + context = context, + sessionId = sessionId, + syncTimeoutSeconds = vectorPreferences.backgroundSyncTimeOut(), + syncDelaySeconds = vectorPreferences.backgroundSyncDelay(), + isNetworkBack = false + ) + .let { + try { + ContextCompat.startForegroundService(context, it) + } catch (ex: Throwable) { + Timber.i("## Sync: Failed to start service, Alarm scheduled to restart service") + scheduleAlarm(context, sessionId, vectorPreferences.backgroundSyncDelay()) + Timber.e(ex) + } + } } companion object { diff --git a/vector/src/main/java/im/vector/app/core/extensions/Session.kt b/vector/src/main/java/im/vector/app/core/extensions/Session.kt index cb87947612..b8cdd83324 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Session.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Session.kt @@ -38,14 +38,19 @@ fun Session.startSyncing(context: Context) { val applicationContext = context.applicationContext if (!hasAlreadySynced()) { // initial sync is done as a service so it can continue below app lifecycle - VectorSyncService.newOneShotIntent(applicationContext, sessionId, 0).also { - try { - ContextCompat.startForegroundService(applicationContext, it) - } catch (ex: Throwable) { - // TODO - Timber.e(ex) - } - } + VectorSyncService.newOneShotIntent( + context = applicationContext, + sessionId = sessionId, + syncTimeoutSeconds = 0 + ) + .let { + try { + ContextCompat.startForegroundService(applicationContext, it) + } catch (ex: Throwable) { + // TODO + Timber.e(ex) + } + } } else { val isAtLeastStarted = ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) Timber.v("--> is at least started? $isAtLeastStarted") diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 2f21d53177..c9b72708f8 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -41,27 +41,27 @@ class VectorSyncService : SyncService() { companion object { - fun newOneShotIntent(context: Context, sessionId: String, timeoutSeconds: Int): Intent { + fun newOneShotIntent(context: Context, + sessionId: String, + syncTimeoutSeconds: Int): Intent { return Intent(context, VectorSyncService::class.java).also { it.putExtra(EXTRA_SESSION_ID, sessionId) - it.putExtra(EXTRA_TIMEOUT_SECONDS, timeoutSeconds) + it.putExtra(EXTRA_TIMEOUT_SECONDS, syncTimeoutSeconds) it.putExtra(EXTRA_PERIODIC, false) } } - fun newPeriodicIntent( - context: Context, - sessionId: String, - timeoutSeconds: Int, - delayInSeconds: Int, - networkBack: Boolean = false - ): Intent { + fun newPeriodicIntent(context: Context, + sessionId: String, + syncTimeoutSeconds: Int, + syncDelaySeconds: Int, + isNetworkBack: Boolean): Intent { return Intent(context, VectorSyncService::class.java).also { it.putExtra(EXTRA_SESSION_ID, sessionId) - it.putExtra(EXTRA_TIMEOUT_SECONDS, timeoutSeconds) + it.putExtra(EXTRA_TIMEOUT_SECONDS, syncTimeoutSeconds) it.putExtra(EXTRA_PERIODIC, true) - it.putExtra(EXTRA_DELAY_SECONDS, delayInSeconds) - it.putExtra(EXTRA_NETWORK_BACK_RESTART, networkBack) + it.putExtra(EXTRA_DELAY_SECONDS, syncDelaySeconds) + it.putExtra(EXTRA_NETWORK_BACK_RESTART, isNetworkBack) } } @@ -154,13 +154,19 @@ class VectorSyncService : SyncService() { } private fun Context.rescheduleSyncService(sessionId: String, - timeout: Int, - delay: Int, + syncTimeoutSeconds: Int, + syncDelaySeconds: Int, isNetworkBack: Boolean) { Timber.d("## Sync: rescheduleSyncService") - val periodicIntent = VectorSyncService.newPeriodicIntent(this, sessionId, timeout, delay, isNetworkBack) + val periodicIntent = VectorSyncService.newPeriodicIntent( + context = this, + sessionId = sessionId, + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds, + isNetworkBack = isNetworkBack + ) - if (isNetworkBack || delay == 0) { + if (isNetworkBack || syncDelaySeconds == 0) { // Do not wait, do the sync now (more reactivity if network back is due to user action) startService(periodicIntent) } else { @@ -169,7 +175,7 @@ private fun Context.rescheduleSyncService(sessionId: String, } else { PendingIntent.getService(this, 0, periodicIntent, 0) } - val firstMillis = System.currentTimeMillis() + delay * 1000L + val firstMillis = System.currentTimeMillis() + syncDelaySeconds * 1000L val alarmMgr = getSystemService()!! if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) From 2b60affd9a6ab7a27b34b1d51eb0323df32b4a6b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 15:23:14 +0100 Subject: [PATCH 209/224] Remove useless param --- .../src/main/java/im/vector/app/core/extensions/Session.kt | 3 +-- .../java/im/vector/app/core/services/VectorSyncService.kt | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/extensions/Session.kt b/vector/src/main/java/im/vector/app/core/extensions/Session.kt index b8cdd83324..10dade70ea 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Session.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Session.kt @@ -40,8 +40,7 @@ fun Session.startSyncing(context: Context) { // initial sync is done as a service so it can continue below app lifecycle VectorSyncService.newOneShotIntent( context = applicationContext, - sessionId = sessionId, - syncTimeoutSeconds = 0 + sessionId = sessionId ) .let { try { diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index c9b72708f8..65b81be384 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -42,11 +42,10 @@ class VectorSyncService : SyncService() { companion object { fun newOneShotIntent(context: Context, - sessionId: String, - syncTimeoutSeconds: Int): Intent { + sessionId: String): Intent { return Intent(context, VectorSyncService::class.java).also { it.putExtra(EXTRA_SESSION_ID, sessionId) - it.putExtra(EXTRA_TIMEOUT_SECONDS, syncTimeoutSeconds) + it.putExtra(EXTRA_TIMEOUT_SECONDS, 0) it.putExtra(EXTRA_PERIODIC, false) } } From b2df107f1777dd6d5643742699733b92fab8689f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 16:11:22 +0100 Subject: [PATCH 210/224] Remove unused params --- .../android/sdk/internal/session/sync/job/SyncService.kt | 8 ++++---- .../java/im/vector/app/core/services/VectorSyncService.kt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index c79b25fb93..01ab47a3b8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -120,7 +120,7 @@ abstract class SyncService : Service() { serviceScope.coroutineContext.cancelChildren() if (!preventReschedule && periodic && sessionId != null && backgroundDetectionObserver.isInBackground) { Timber.d("## Sync: Reschedule service in $syncDelaySeconds sec") - onRescheduleAsked(sessionId ?: "", false, syncTimeoutSeconds, syncDelaySeconds) + onRescheduleAsked(sessionId ?: "", syncTimeoutSeconds, syncDelaySeconds) } super.onDestroy() } @@ -177,7 +177,7 @@ abstract class SyncService : Service() { // Network might be off, no need to reschedule endless alarms :/ preventReschedule = true // Instead start a work to restart background sync when network is on - onNetworkError(sessionId ?: "", isInitialSync, syncTimeoutSeconds, syncDelaySeconds) + onNetworkError(sessionId ?: "", syncTimeoutSeconds, syncDelaySeconds) } // JobCancellation could be caught here when onDestroy cancels the coroutine context if (isRunning.get()) stopMe() @@ -217,9 +217,9 @@ abstract class SyncService : Service() { abstract fun onStart(isInitialSync: Boolean) - abstract fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) + abstract fun onRescheduleAsked(sessionId: String, timeout: Int, delay: Int) - abstract fun onNetworkError(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) + abstract fun onNetworkError(sessionId: String, timeout: Int, delay: Int) override fun onBind(intent: Intent?): IBinder? { return null diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 65b81be384..5b732a5e3c 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -92,11 +92,11 @@ class VectorSyncService : SyncService() { startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification) } - override fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { + override fun onRescheduleAsked(sessionId: String, timeout: Int, delay: Int) { rescheduleSyncService(sessionId, timeout, delay, false) } - override fun onNetworkError(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) { + override fun onNetworkError(sessionId: String, timeout: Int, delay: Int) { Timber.d("## Sync: A network error occurred during sync") val rescheduleSyncWorkRequest: WorkRequest = OneTimeWorkRequestBuilder() From 50ba13135039327d262081c6f8999fc67dc028ee Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 16:18:29 +0100 Subject: [PATCH 211/224] More renaming --- .../sdk/internal/session/sync/job/SyncService.kt | 16 ++++++++++++---- .../app/core/services/VectorSyncService.kt | 12 ++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index 01ab47a3b8..f3c2235dc9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -120,7 +120,11 @@ abstract class SyncService : Service() { serviceScope.coroutineContext.cancelChildren() if (!preventReschedule && periodic && sessionId != null && backgroundDetectionObserver.isInBackground) { Timber.d("## Sync: Reschedule service in $syncDelaySeconds sec") - onRescheduleAsked(sessionId ?: "", syncTimeoutSeconds, syncDelaySeconds) + onRescheduleAsked( + sessionId = sessionId ?: "", + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds + ) } super.onDestroy() } @@ -177,7 +181,11 @@ abstract class SyncService : Service() { // Network might be off, no need to reschedule endless alarms :/ preventReschedule = true // Instead start a work to restart background sync when network is on - onNetworkError(sessionId ?: "", syncTimeoutSeconds, syncDelaySeconds) + onNetworkError( + sessionId = sessionId ?: "", + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds + ) } // JobCancellation could be caught here when onDestroy cancels the coroutine context if (isRunning.get()) stopMe() @@ -217,9 +225,9 @@ abstract class SyncService : Service() { abstract fun onStart(isInitialSync: Boolean) - abstract fun onRescheduleAsked(sessionId: String, timeout: Int, delay: Int) + abstract fun onRescheduleAsked(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int) - abstract fun onNetworkError(sessionId: String, timeout: Int, delay: Int) + abstract fun onNetworkError(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int) override fun onBind(intent: Intent?): IBinder? { return null diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 5b732a5e3c..3f096376ff 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -92,15 +92,19 @@ class VectorSyncService : SyncService() { startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification) } - override fun onRescheduleAsked(sessionId: String, timeout: Int, delay: Int) { - rescheduleSyncService(sessionId, timeout, delay, false) + override fun onRescheduleAsked(sessionId: String, + syncTimeoutSeconds: Int, + syncDelaySeconds: Int) { + rescheduleSyncService(sessionId, syncTimeoutSeconds, syncDelaySeconds, false) } - override fun onNetworkError(sessionId: String, timeout: Int, delay: Int) { + override fun onNetworkError(sessionId: String, + syncTimeoutSeconds: Int, + syncDelaySeconds: Int) { Timber.d("## Sync: A network error occurred during sync") val rescheduleSyncWorkRequest: WorkRequest = OneTimeWorkRequestBuilder() - .setInputData(RestartWhenNetworkOn.createInputData(sessionId, timeout, delay)) + .setInputData(RestartWhenNetworkOn.createInputData(sessionId, syncTimeoutSeconds, syncDelaySeconds)) .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() From 2ea45185d41ff3b61db39a52163241c23b11415e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 16:26:52 +0100 Subject: [PATCH 212/224] Ensure the service is restarted with the correct intent --- .../internal/session/sync/job/SyncService.kt | 5 +- .../app/core/services/VectorSyncService.kt | 58 ++++++++++++++----- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index f3c2235dc9..cce169c246 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -184,7 +184,8 @@ abstract class SyncService : Service() { onNetworkError( sessionId = sessionId ?: "", syncTimeoutSeconds = syncTimeoutSeconds, - syncDelaySeconds = syncDelaySeconds + syncDelaySeconds = syncDelaySeconds, + isPeriodic = periodic ) } // JobCancellation could be caught here when onDestroy cancels the coroutine context @@ -227,7 +228,7 @@ abstract class SyncService : Service() { abstract fun onRescheduleAsked(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int) - abstract fun onNetworkError(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int) + abstract fun onNetworkError(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int, isPeriodic: Boolean) override fun onBind(intent: Intent?): IBinder? { return null diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 3f096376ff..4b5c470ad2 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -95,16 +95,23 @@ class VectorSyncService : SyncService() { override fun onRescheduleAsked(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int) { - rescheduleSyncService(sessionId, syncTimeoutSeconds, syncDelaySeconds, false) + rescheduleSyncService( + sessionId = sessionId, + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds, + isPeriodic = true, + isNetworkBack = false + ) } override fun onNetworkError(sessionId: String, syncTimeoutSeconds: Int, - syncDelaySeconds: Int) { + syncDelaySeconds: Int, + isPeriodic: Boolean) { Timber.d("## Sync: A network error occurred during sync") val rescheduleSyncWorkRequest: WorkRequest = OneTimeWorkRequestBuilder() - .setInputData(RestartWhenNetworkOn.createInputData(sessionId, syncTimeoutSeconds, syncDelaySeconds)) + .setInputData(RestartWhenNetworkOn.createInputData(sessionId, syncTimeoutSeconds, syncDelaySeconds, isPeriodic)) .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() @@ -135,23 +142,36 @@ class VectorSyncService : SyncService() { val sessionId = inputData.getString(KEY_SESSION_ID) ?: return Result.failure() val timeout = inputData.getInt(KEY_TIMEOUT, BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS) val delay = inputData.getInt(KEY_DELAY, BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS) - applicationContext.rescheduleSyncService(sessionId, timeout, delay, true) + val isPeriodic = inputData.getBoolean(KEY_IS_PERIODIC, false) + applicationContext.rescheduleSyncService( + sessionId = sessionId, + syncTimeoutSeconds = timeout, + syncDelaySeconds = delay, + isPeriodic = isPeriodic, + isNetworkBack = true + ) // Indicate whether the work finished successfully with the Result return Result.success() } companion object { - fun createInputData(sessionId: String, timeout: Int, delay: Int): Data { + fun createInputData(sessionId: String, + timeout: Int, + delay: Int, + isPeriodic: Boolean + ): Data { return Data.Builder() .putString(KEY_SESSION_ID, sessionId) .putInt(KEY_TIMEOUT, timeout) .putInt(KEY_DELAY, delay) + .putBoolean(KEY_IS_PERIODIC, isPeriodic) .build() } private const val KEY_SESSION_ID = "sessionId" private const val KEY_TIMEOUT = "timeout" private const val KEY_DELAY = "delay" + private const val KEY_IS_PERIODIC = "isPeriodic" } } } @@ -159,24 +179,32 @@ class VectorSyncService : SyncService() { private fun Context.rescheduleSyncService(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int, + isPeriodic: Boolean, isNetworkBack: Boolean) { Timber.d("## Sync: rescheduleSyncService") - val periodicIntent = VectorSyncService.newPeriodicIntent( - context = this, - sessionId = sessionId, - syncTimeoutSeconds = syncTimeoutSeconds, - syncDelaySeconds = syncDelaySeconds, - isNetworkBack = isNetworkBack - ) + val intent = if (isPeriodic) { + VectorSyncService.newPeriodicIntent( + context = this, + sessionId = sessionId, + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds, + isNetworkBack = isNetworkBack + ) + } else { + VectorSyncService.newOneShotIntent( + context = this, + sessionId = sessionId + ) + } if (isNetworkBack || syncDelaySeconds == 0) { // Do not wait, do the sync now (more reactivity if network back is due to user action) - startService(periodicIntent) + startService(intent) } else { val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - PendingIntent.getForegroundService(this, 0, periodicIntent, 0) + PendingIntent.getForegroundService(this, 0, intent, 0) } else { - PendingIntent.getService(this, 0, periodicIntent, 0) + PendingIntent.getService(this, 0, intent, 0) } val firstMillis = System.currentTimeMillis() + syncDelaySeconds * 1000L val alarmMgr = getSystemService()!! From d4c8f56c6e91a7697d992ef4a813116dad817b78 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 16:29:05 +0100 Subject: [PATCH 213/224] More renaming --- .../app/core/services/VectorSyncService.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 4b5c470ad2..2a00e94976 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -140,13 +140,13 @@ class VectorSyncService : SyncService() { override fun doWork(): Result { Timber.d("## Sync: RestartWhenNetworkOn.doWork()") val sessionId = inputData.getString(KEY_SESSION_ID) ?: return Result.failure() - val timeout = inputData.getInt(KEY_TIMEOUT, BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS) - val delay = inputData.getInt(KEY_DELAY, BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS) + val syncTimeoutSeconds = inputData.getInt(KEY_SYNC_TIMEOUT_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS) + val syncDelaySeconds = inputData.getInt(KEY_SYNC_DELAY_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS) val isPeriodic = inputData.getBoolean(KEY_IS_PERIODIC, false) applicationContext.rescheduleSyncService( sessionId = sessionId, - syncTimeoutSeconds = timeout, - syncDelaySeconds = delay, + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds, isPeriodic = isPeriodic, isNetworkBack = true ) @@ -156,21 +156,21 @@ class VectorSyncService : SyncService() { companion object { fun createInputData(sessionId: String, - timeout: Int, - delay: Int, + syncTimeoutSeconds: Int, + syncDelaySeconds: Int, isPeriodic: Boolean ): Data { return Data.Builder() .putString(KEY_SESSION_ID, sessionId) - .putInt(KEY_TIMEOUT, timeout) - .putInt(KEY_DELAY, delay) + .putInt(KEY_SYNC_TIMEOUT_SECONDS, syncTimeoutSeconds) + .putInt(KEY_SYNC_DELAY_SECONDS, syncDelaySeconds) .putBoolean(KEY_IS_PERIODIC, isPeriodic) .build() } private const val KEY_SESSION_ID = "sessionId" - private const val KEY_TIMEOUT = "timeout" - private const val KEY_DELAY = "delay" + private const val KEY_SYNC_TIMEOUT_SECONDS = "timeout" + private const val KEY_SYNC_DELAY_SECONDS = "delay" private const val KEY_IS_PERIODIC = "isPeriodic" } } From 7446b12827f12d0cc32caa55fa6f89d0df659eec Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Jan 2021 18:16:35 +0100 Subject: [PATCH 214/224] Fix request too large Uri error when joining a room --- CHANGES.md | 1 + .../room/membership/joining/JoinRoomTask.kt | 6 +++++- .../roompreview/RoomPreviewViewModel.kt | 16 ++++++++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d039be252d..d0cfcf2089 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,7 @@ Bugfix 🐛: - Tapping drawer having more than 1 room in notifications gives "malformed link" error (#2605) - Sent image not displayed when opened immediately after sending (#409) - Initial sync is not retried correctly when there is some network error. (#2632) + - Fix request too large Uri error when joining a room Translations 🗣: - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt index 140c6841f5..3b7639d42f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt @@ -55,7 +55,11 @@ internal class DefaultJoinRoomTask @Inject constructor( roomChangeMembershipStateDataSource.updateState(params.roomIdOrAlias, ChangeMembershipState.Joining) val joinRoomResponse = try { executeRequest(globalErrorReceiver) { - apiCall = roomAPI.join(params.roomIdOrAlias, params.viaServers, mapOf("reason" to params.reason)) + apiCall = roomAPI.join( + roomIdOrAlias = params.roomIdOrAlias, + viaServers = params.viaServers.take(3), + params = mapOf("reason" to params.reason) + ) } } catch (failure: Throwable) { roomChangeMembershipStateDataSource.updateState(params.roomIdOrAlias, ChangeMembershipState.FailedJoining(failure)) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt index 72c4c58a42..63b9a50546 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt @@ -84,22 +84,34 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini when (peekResult) { is PeekResult.Success -> { setState { + // Do not override what we had from the permalink + val newHomeServers = if (homeServers.isEmpty()) { + peekResult.viaServers.take(3) + } else { + homeServers + } copy( roomId = peekResult.roomId, avatarUrl = peekResult.avatarUrl, roomAlias = peekResult.alias ?: initialState.roomAlias, roomTopic = peekResult.topic, - homeServers = peekResult.viaServers, + homeServers = newHomeServers, peekingState = Success(PeekingState.FOUND) ) } } is PeekResult.PeekingNotAllowed -> { setState { + // Do not override what we had from the permalink + val newHomeServers = if (homeServers.isEmpty()) { + peekResult.viaServers.take(3) + } else { + homeServers + } copy( roomId = peekResult.roomId, roomAlias = peekResult.alias ?: initialState.roomAlias, - homeServers = peekResult.viaServers, + homeServers = newHomeServers, peekingState = Success(PeekingState.NO_ACCESS) ) } From dbaaa07dad3a0065792f8e128cce78bf394ed728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=90=D7=91=D7=99=20=D7=98=D7=99=D7=99=D7=91?= Date: Tue, 12 Jan 2021 20:12:33 +0000 Subject: [PATCH 215/224] Translated using Weblate (Hebrew) Currently translated at 52.1% (1052 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 143a156916..1cfffd1f69 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -1206,4 +1206,28 @@ שיתוף שתף ללא אימות אמת + כפתור Enter על המקלדת הרכה ישלח הודעה במקום להוסיף מעבר שורה + שלח הודעה עם Enter + הצג תצוגה מקדימה של מדיה לפני השליחה + רטוט בעת אזכור משתמש + כולל שינויים באווטאר ושמות תצוגה. + הצג אירועי חשבון + הזמנות, בעיטות ואיסורים אינם מושפעים. + הראה אירועי הצטרפות ועזיבה + כולל אירועי הזמנה / הצטרפות / שמאל / בעיטה / איסור ושינוי שם אווטאר / תצוגה. + הצג אירועים של מדינת החברים בחדר + לחץ על אישורי הקריאה לרשימה מפורטת. + הצג קבלות קריאה + הצג חותמות זמן בפורמט של 12 שעות + הצג חותמות זמן לכל ההודעות + עצב הודעות באמצעות תחביר הסימון לפני שהן נשלחות. זה מאפשר עיצוב מתקדם כגון שימוש בכוכביות להצגת טקסט נטוי. + עיצוב Markdown + הודע למשתמשים אחרים שאתה מקליד. + שלח הודעות הקלדה + תצוגה מקדימה של קישורים בצ\'אט כאשר שרת הבית שלך תומך בתכונה זו. + תצוגה מקדימה של כתובת אתר מוטמעת + מושבים + הצמד חדרים עם הודעות שלא נקראו + הצמד חדרים עם התראות שלא נענו + ארץ ספר הטלפונים \ No newline at end of file From 0750c7763c9e4f55286e98a752effcff1e1fa0ce Mon Sep 17 00:00:00 2001 From: argaman Date: Tue, 12 Jan 2021 19:29:28 +0000 Subject: [PATCH 216/224] Translated using Weblate (Hebrew) Currently translated at 52.1% (1052 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 1cfffd1f69..59a1fb7014 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -1230,4 +1230,7 @@ הצמד חדרים עם הודעות שלא נקראו הצמד חדרים עם התראות שלא נענו ארץ ספר הטלפונים + מסך ראשי + הרשאת אנשי קשר + אנשי קשר מקומיים \ No newline at end of file From 1f1eeccc3224fd392b305b59635478863357340f Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 13 Jan 2021 13:28:46 +0300 Subject: [PATCH 217/224] Option to hide emoji keyboard is added. --- CHANGES.md | 1 + .../features/home/room/detail/RoomDetailFragment.kt | 2 ++ .../vector/app/features/settings/VectorPreferences.kt | 11 +++++++++++ vector/src/main/res/values/strings.xml | 2 ++ .../src/main/res/xml/vector_settings_preferences.xml | 6 ++++++ 5 files changed, 22 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index d0cfcf2089..a4a3f7ee73 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Features ✨: Improvements 🙌: - Add System theme option and set as default (#904, #2387) - Warn user when they are leaving a not public room (#1460) + - Option to disable emoji keyboard (#2563) Bugfix 🐛: - Unspecced msgType field in m.sticker (#2580) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 8d0ed34c1e..e134230c61 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -1164,6 +1164,8 @@ class RoomDetailFragment @Inject constructor( } else false } + views.composerLayout.views.composerEmojiButton.isVisible = vectorPreferences.showEmojiKeyboard() + views.composerLayout.callback = object : TextComposerView.Callback { override fun onAddAttachment() { if (!::attachmentTypeSelector.isInitialized) { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 16be2b1552..d3ef36a80b 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -98,6 +98,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { private const val SETTINGS_VIBRATE_ON_MENTION_KEY = "SETTINGS_VIBRATE_ON_MENTION_KEY" private const val SETTINGS_SEND_MESSAGE_WITH_ENTER = "SETTINGS_SEND_MESSAGE_WITH_ENTER" private const val SETTINGS_ENABLE_CHAT_EFFECTS = "SETTINGS_ENABLE_CHAT_EFFECTS" + private const val SETTINGS_SHOW_EMOJI_KEYBOARD = "SETTINGS_SHOW_EMOJI_KEYBOARD" // Help private const val SETTINGS_SHOULD_SHOW_HELP_ON_ROOM_LIST_KEY = "SETTINGS_SHOULD_SHOW_HELP_ON_ROOM_LIST_KEY" @@ -207,6 +208,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { SETTINGS_MEDIA_SAVING_PERIOD_SELECTED_KEY, SETTINGS_PREVIEW_MEDIA_BEFORE_SENDING_KEY, SETTINGS_SEND_MESSAGE_WITH_ENTER, + SETTINGS_SHOW_EMOJI_KEYBOARD, SETTINGS_PIN_UNREAD_MESSAGES_PREFERENCE_KEY, SETTINGS_PIN_MISSED_NOTIFICATIONS_PREFERENCE_KEY, @@ -822,6 +824,15 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_SEND_MESSAGE_WITH_ENTER, false) } + /** + * Tells if the emoji keyboard button should be visible or not. + * + * @return true to show emoji keyboard button. + */ + fun showEmojiKeyboard(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_SHOW_EMOJI_KEYBOARD, true) + } + /** * Tells if the rage shake is used. * diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 8612bc43f1..1f282115e0 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -917,6 +917,8 @@ Preview media before sending Send message with enter Enter button of the soft keyboard will send message instead of adding a line break + Show emoji keyboard + Add a button on message composer to open emoji keyboard Secure Backup Manage diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 6297b89e6c..4150432149 100644 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -49,6 +49,12 @@ android:summary="@string/settings_send_message_with_enter_summary" android:title="@string/settings_send_message_with_enter" /> + + From f7ed94c6e9bfff7f956c16506b46a873c151703d Mon Sep 17 00:00:00 2001 From: argaman Date: Tue, 12 Jan 2021 21:46:06 +0000 Subject: [PATCH 218/224] Translated using Weblate (Hebrew) Currently translated at 52.1% (1052 of 2018 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 59a1fb7014..8b4e019918 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -1217,7 +1217,7 @@ כולל אירועי הזמנה / הצטרפות / שמאל / בעיטה / איסור ושינוי שם אווטאר / תצוגה. הצג אירועים של מדינת החברים בחדר לחץ על אישורי הקריאה לרשימה מפורטת. - הצג קבלות קריאה + הצג קבלות הצג קבלות קריאה הצג חותמות זמן בפורמט של 12 שעות הצג חותמות זמן לכל ההודעות עצב הודעות באמצעות תחביר הסימון לפני שהן נשלחות. זה מאפשר עיצוב מתקדם כגון שימוש בכוכביות להצגת טקסט נטוי. From 801f2860e2b4c33a2c66af0def667b184d82ad55 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Thu, 14 Jan 2021 02:54:09 +0000 Subject: [PATCH 219/224] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (2055 of 2055 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hant/ --- vector/src/main/res/values-zh-rTW/strings.xml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index da24c2d878..f0a591b93d 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -2241,4 +2241,41 @@ 對可讀取歷史紀錄的人的變更將僅試用於此聊天室中的未來訊息。現有歷史紀錄的可見性將保持不便。 取消發佈 新增 + 傳送雪 ❄️ + 傳送五彩紙屑 🎉 + 與雪一同傳送指定的訊息 + 與五彩紙屑一同傳送指定的訊息 + 清除歷史紀錄 + 單一登入 + 使用 %s 登入 + 使用 %s 註冊 + 繼續 %s + + 使用 /confetti 指令或傳送包含 ❄️ 或 🎉 的訊息 + 顯示聊天效果 + 變更主題 + 升級聊天室 + 傳送 m.room.server_acl 活動 + 變更權限 + 變更聊天室名稱 + 變更歷史紀錄可見性 + 啟用聊天室加密 + 變更聊天室的主要位置 + 變更聊天室大頭照 + 修改小工具 + 通知每個人 + 移除其他人傳送的訊息 + 封鎖使用者 + 踢除使用者 + 變更設定 + 邀請使用者 + 傳送訊息 + 預設角色 + 您無權更新聊天室各部份所需的角色 + 選取聊天室各部份所需的角色 + 權限 + 檢視並更新聊天室各部份所需的角色。 + 聊天室權限 + 此聊天室不公開。沒有邀請,您將無法重新加入。 + 系統預設值 \ No newline at end of file From e91dbfbf2cb29405e77cfee6f3650a724804ff95 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Thu, 14 Jan 2021 02:43:19 +0000 Subject: [PATCH 220/224] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (7 of 7 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/zh_Hant/ --- fastlane/metadata/android/zh_Hant/changelogs/40100120.txt | 2 ++ fastlane/metadata/android/zh_Hant/changelogs/40100130.txt | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 fastlane/metadata/android/zh_Hant/changelogs/40100120.txt create mode 100644 fastlane/metadata/android/zh_Hant/changelogs/40100130.txt diff --git a/fastlane/metadata/android/zh_Hant/changelogs/40100120.txt b/fastlane/metadata/android/zh_Hant/changelogs/40100120.txt new file mode 100644 index 0000000000..846126af63 --- /dev/null +++ b/fastlane/metadata/android/zh_Hant/changelogs/40100120.txt @@ -0,0 +1,2 @@ +此版本中的主要變更:URL 預覽、新的表情符號鍵盤、新的聊天室設定功能以及聖誕節降雪! +完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.0.12 diff --git a/fastlane/metadata/android/zh_Hant/changelogs/40100130.txt b/fastlane/metadata/android/zh_Hant/changelogs/40100130.txt new file mode 100644 index 0000000000..846126af63 --- /dev/null +++ b/fastlane/metadata/android/zh_Hant/changelogs/40100130.txt @@ -0,0 +1,2 @@ +此版本中的主要變更:URL 預覽、新的表情符號鍵盤、新的聊天室設定功能以及聖誕節降雪! +完整變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.0.12 From e097c92458fc248983a5d6537f6d65d4ad6aa682 Mon Sep 17 00:00:00 2001 From: Flat Earth Israel Association Date: Wed, 13 Jan 2021 23:53:27 +0000 Subject: [PATCH 221/224] Translated using Weblate (Hebrew) Currently translated at 54.2% (1114 of 2055 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/he/ --- vector/src/main/res/values-he/strings.xml | 69 +++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 8b4e019918..e9087dbe29 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -1233,4 +1233,73 @@ מסך ראשי הרשאת אנשי קשר אנשי קשר מקומיים + לעולם אל תאבד הודעות מוצפנות + להגן מפני אובדן גישה להודעות ונתונים מוצפנים + גיבוי מאובטח + התחל להשתמש בגיבוי מפתח + לעולם אל תאבד הודעות מוצפנות + זה היה אני + גיבוי מפתח חדש גיבוי חדש של מפתח הודעות מאובטח. +\n +\nאם לא הגדרת את שיטת השחזור החדשה, ייתכן שתוקף מנסה לגשת לחשבונך. שנה את סיסמת החשבון שלך והגדר מיד שיטת שחזור חדשה בהגדרות. + גיבוי מפתח חדש + מחק גיבוי למחוק את מפתחות ההצפנה המגובים שלך מהשרת\? לא תוכל עוד להשתמש במפתח השחזור שלך כדי לקרוא את היסטוריית ההודעות המוצפנת. + מחק את הגיבוי + בודק מצב גיבוי + מחיקת הגיבוי נכשלה (%s) + מוחק גיבוי … + כדי להשתמש בגיבוי מקשים בהפעלה זו, שחזר באמצעות משפט הסיסמה או מפתח השחזור שלך כעת. + נכשל קבלת פרטי אמון לגיבוי (%s). + לגיבוי יש חתימה לא חוקית מהפעלה %s לא מאומתת + לגיבוי יש חתימה לא חוקית מההפעלה %s המאומתת + לגיבוי יש חתימה חוקית מהפעלה %s לא מאומתת + לגיבוי יש חתימה מהפעלה לא ידועה עם מזהה %s. + לגיבוי יש חתימה חוקית מההפעלה המאומתת %s. + לגיבוי יש חתימה חוקית מהפגישה זו. + לא מגובים את המפתחות שלך מהפגישה זו. + גיבוי המפתח אינו פעיל בהפעלה זו. + גיבוי המפתח הוגדר כהלכה להפעלה זו. + מחק את הגיבוי + שחזר מגיבוי + הצפנת מושב אינה מופעלת + השגת הגרסה האחרונה של מפתחות השחזור (%s) נכשלה. + הגיבוי שוחזר %s! + לא ניתן היה לפענח את הגיבוי באמצעות מפתח שחזור זה: ודא שהזנת את מפתח השחזור הנכון. + אנא הכנס מפתח שחזור + בטל נעילת היסטוריה + מייבא מפתחות … + מוריד מקשים … + מפתח שחזור מחשוב … + שחזור הגיבוי: + שגיאת רשת: אנא בדוק את החיבור שלך ונסה שוב. + לא ניתן לפענח גיבוי באמצעות ביטוי סיסמה זה: אנא ודא שהזנת את ביטוי הסיסמה לשחזור הנכון. + איבדת את מפתח ההתאוששות שלך\? אתה יכול להגדיר אחד חדש בהגדרות. + שחזור הודעות + הזן מפתח שחזור + השתמש במפתח השחזור שלך כדי לפתוח את היסטוריית ההודעות המוצפנות שלך + אינך יודע את ביטוי הסיסמה לשחזור שלך, אתה יכול %s. + השתמש במפתח השחזור שלך + השתמש בביטוי הסיסמה לשחזור כדי לבטל את נעילת היסטוריית ההודעות המוצפנות שלך + מביא גרסת גיבוי … + אתה עלול לאבד גישה להודעות שלך אם אתה מתנתק או מאבד מכשיר זה. + האם אתה בטוח\? + מפתחות ההצפנה שלך מגובים כעת ברקע לשרת הבית שלך. הגיבוי הראשוני עשוי להימשך מספר דקות. + הגיבוי התחיל + שגיאה לא צפויה + מפתח שחזור + יצירת מפתח שחזור באמצעות ביטוי סיסמה, תהליך זה יכול להימשך מספר שניות. + שתף מפתח שחזור עם … + בבקשה צרו העתק + עצור + החלפה + נראה שכבר יש לך גיבוי מפתח הגדרה מהפעלה אחרת. האם אתה רוצה להחליף אותו לזה שאתה יוצר\? + גיבוי כבר קיים בשרת הבית שלך + מפתח השחזור נשמר. + מפתח השחזור נשמר ב- \'%s\'. +\n +\nאזהרה: קובץ זה עשוי להימחק אם הסרת ההתקנה של היישום. + שמירת קובץ בשם + שיתוף + שמור מפתח שחזור + הכנתי עותק \ No newline at end of file From d6ef3ea08e4e1d41dbc628b5097722c966406dd2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Jan 2021 13:59:20 +0100 Subject: [PATCH 222/224] Fix lint issues --- .../src/main/res/values-lv/strings.xml | 2 +- vector/src/main/res/values-el/strings.xml | 4 +- vector/src/main/res/values-he/strings.xml | 67 +++++++------------ vector/src/main/res/values-vi/strings.xml | 4 +- 4 files changed, 30 insertions(+), 47 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-lv/strings.xml b/matrix-sdk-android/src/main/res/values-lv/strings.xml index b4478be9be..ec107b47d6 100644 --- a/matrix-sdk-android/src/main/res/values-lv/strings.xml +++ b/matrix-sdk-android/src/main/res/values-lv/strings.xml @@ -62,7 +62,7 @@ Tu nomainījis savu attēlojamo vārdu uz %1$s Tu nomainīji savu avataru Tu atsauci %1$s uzaicinājumu - Tu nobanoji 1$s + Tu nobanoji %1$s Tu atbanoji %1$s Tu izspēri %1$s Tu noraidīji uzaicinājumu diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index c5242447c9..5eb8750c15 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -513,13 +513,13 @@ Αποστολή μηνύματος (κρυπτογραφημένο)… Αποστολή κρυπτογραφημένου μηνύματος… %1$s & %2$s & άλλοι γράφουν… - % γράφει… + %s γράφει… %1$s & %2$s γράφουν… Συνομιλία Διεύθυνση ηλεκτρονικού ταχυδρομίου ή Matrix ID Πρόσκληση μέσω ID χρήστη Μόνο χρήστες Matrix - Ευρετήριο χρηστών + Ευρετήριο χρηστών (%s) Είστε σίγουροι ότι θέλετε να προσκαλέσετε τους %s σε αυτή την συζήτηση; Λόγος Δεν εξακριβώθηκε η ταυτότητα του εξωτερικού διακομιστή. diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index e9087dbe29..177548ea50 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -58,8 +58,6 @@ לא יכול להתחיל את השיחה, נסה שוב מאוחר יותר וידאו קול - שיחת ועידה מתמשכת. -\nהצטרף כ-% 1 $ s או% 2 $ s התחל לצ\'וטט אתחול השהה @@ -173,7 +171,6 @@ הצטרף אל חדר קרא שלח פנימה - התקדמות (%%%) לא ניתן היה לשלוח את דוח הבאג (%s) דוח הבאג נשלח בהצלחה טלטול זעם כדי לדווח על באג @@ -215,7 +212,7 @@ \n \nהוצאת מכל ההפעלות ולא תקבל עוד התראות דחיפה. כדי להפעיל מחדש התראות, התחבר מחדש בכל מכשיר. אימות כתובת הדוא\"ל נכשל: ודא שלחצת על הקישור בדוא\"ל - דוא\"ל נשלח אל% s. לאחר שתעקוב אחר הקישור שהוא מכיל, לחץ למטה. + דוא\"ל נשלח אל%s. לאחר שתעקוב אחר הקישור שהוא מכיל, לחץ למטה. יש להזין סיסמה חדשה. יש להזין את כתובת הדוא\"ל המקושרת לחשבונך. כדי לאפס את הסיסמה שלך, הזן את כתובת הדוא\"ל המקושרת לחשבונך: @@ -288,10 +285,7 @@ \nאנא בקש ממנהל שרת הבית שלך להגדיר שרת TURN על מנת שהשיחות יעבדו בצורה אמינה. שיחת האלמנט נכשלה אל תשאל אותי שוב - נסה להשתמש ב-% s - אנא בקש ממנהל שרת הבית שלך (% 1 $ s) להגדיר שרת TURN כדי שהשיחות יעבדו בצורה אמינה. -\n -\nלחלופין, אתה יכול לנסות להשתמש בשרת הציבורי ב-% 2 $ s, אך זה לא יהיה אמין כל כך, והוא ישתף את כתובת ה- IP שלך עם השרת הזה. תוכל לנהל זאת גם בהגדרות. + נסה להשתמש ב-%s השיחה נכשלה עקב שרת שהוגדר כהלכה האם אתה בטוח שברצונך להתחיל שיחת וידאו\? האם אתה בטוח שברצונך להתחיל שיחה קולית\? @@ -299,10 +293,10 @@ הוסף שרת זהות בהגדרות שלך כדי לבצע פעולה זו. זו תצוגה מקדימה של החדר הזה. אינטראקציות בחדר הושבתו. חדר - אתה מנסה לגשת ל-% s. האם תרצה להצטרף על מנת להשתתף בדיון\? - הזמנה זו נשלחה אל% s, שאינה משויכת לחשבון זה. + אתה מנסה לגשת ל-%s. האם תרצה להצטרף על מנת להשתתף בדיון\? + הזמנה זו נשלחה אל%s, שאינה משויכת לחשבון זה. \nייתכן שתרצה להתחבר עם חשבון אחר, או להוסיף דוא\"ל זה לחשבונך. - הוזמנת להצטרף לחדר זה על ידי% s + הוזמנת להצטרף לחדר זה על ידי%s קפיצה להודעה הראשונה שלא נקראה. מסנכרן… פתח כותרת @@ -345,7 +339,7 @@ חיבור המדיה נכשל הצד המרוחק לא הצליח להרים. חזור לשיחה - שיחה פעילה (% s) + שיחה פעילה (%s) שיחת וידאו מתבצעת … במהלך התקשרות… שיחה קולית נכנסת @@ -358,7 +352,7 @@ שִׂיחָה בחר רינגטון לשיחות: רינגטון שיחה נכנסת - ישתמש ב-% s כסיוע כאשר השרת הביתי שלך אינו מציע כזה (כתובת ה- IP שלך תשותף במהלך שיחה) + ישתמש ב-%s כסיוע כאשר השרת הביתי שלך אינו מציע כזה (כתובת ה- IP שלך תשותף במהלך שיחה) אפשר שרת עזרה לשיחות השתמש ברינגטון ברירת המחדל של אלמנט לשיחות נכנסות בקש אישור לפני שמתחילים בשיחה @@ -422,7 +416,7 @@ % d שניות עיכוב בין כל סינכרון - % s + %s \nהסנכרון עשוי להידחות בהתאם למשאבים (סוללה) או מצב ההתקן (שינה). מרווח סינכרון מועדף פסק-זמן לבקשה לסנכרון @@ -470,9 +464,9 @@ השבת הגבלות מגבלות רקע מופעלות עבור Element. \nהעבודה שהאפליקציה מנסה לעשות תוגבל באגרסיביות בזמן שהיא ברקע, וזה עלול להשפיע על ההודעות. -\n% 1 $ s +\n%1$s מגבלות רקע מושבתות עבור Element. יש להריץ בדיקה זו באמצעות נתונים ניידים (ללא WIFI). -\n% 1 $ s +\n%1$s בדוק מגבלות רקע הפעל את התחלה לאחר אתחול השירות לא יופעל עם הפעלת המכשיר מחדש, לא תקבל התראות עד שאלמנט ייפתח לפחות פעם אחת. @@ -495,24 +489,24 @@ היישום מקבל PUSH היישום ממתין ל- PUSH נכשל רישום אסימון FCM ל- HomeServer: -\n% 1 $ s +\n%1$s אסימון FCM נרשם בהצלחה ל- HomeServer. רישום אסימונים הוסף חשבון - [% 1 $ s] + [%1$s] \nשגיאה זו אינה בשליטה על אלמנט. אין חשבון Google בטלפון. אנא פתח את מנהל החשבון והוסף חשבון Google. - [% 1 $ s] + [%1$s] \nשגיאה זו אינה בשליטה על אלמנט. זה יכול להתרחש מכמה סיבות. אולי זה יעבוד אם תנסה שוב מאוחר יותר, תוכל גם לבדוק ששירות Google Play אינו מוגבל בשימוש נתונים בהגדרות המערכת, או ששעון המכשיר שלך תקין, או שזה יכול לקרות ב- ROM מותאם אישית. - [% 1 $ s] + [%1$s] \nשגיאה זו איננה בשליטה על Element ולפי גוגל, שגיאה זו מצביעה על כך שלמכשיר יש יותר מדי אפליקציות הרשומות ב- FCM. השגיאה מתרחשת רק במקרים שבהם ישנם מספרים קיצוניים של אפליקציות, כך שהיא לא אמורה להשפיע על המשתמש הממוצע. נכשל באחזור אסימון FCM: -\n% 1 $ s +\n%1$s אסימון FCM אוחזר בהצלחה: -\n% 1 $ s +\n%1$s אסימון Firebase תקן שירותי Google Play אלמנט משתמש בשירותי Google Play כדי להעביר הודעות פוש אך נראה שהוא אינו מוגדר כהלכה: -\n% 1 $ s +\n%1$s ה- APK של שירותי Google Play זמין ומעודכן. בדיקת שירותי הפעלה בדוק בהגדרות @@ -546,7 +540,7 @@ אם מנהל השרת אמר שזה צפוי, ודא שטביעת האצבע שלמטה תואמת את טביעת האצבע שמספקת אותם. יכול להיות שמישהו מיירט את התעבורה שלך בזדון, או שהטלפון שלך לא סומך על האישור שמספק השרת המרוחק. לא ניתן לאמת את זהות השרת המרוחק. - טביעת אצבע (s%): + טביעת אצבע (%s): התעלם יציאה אל תתן אמון @@ -564,21 +558,20 @@ שלח תשובה מוצפנת … שלח הודעה (לא מוצפן) … שלח הודעה מוצפנת … - % 1 $ s &% 2 $ s ואחרים מקלידים … - % 1 $ s &% 2 $ s מקלידים … - % s מקליד … + %1$s &%2$s ואחרים מקלידים … + %1$s &%2$s מקלידים … + %s מקליד … חפש אימייל או מזהה מטריקס אנא הזן כתובת דוא\"ל אחת או יותר או מזהה מטריקס הזמן משתמש לפי מזהה משתמשי מטריקס בלבד - תיקיית משתמש (s%) - אנשי קשר מקומיים (% d) + אנשי קשר מקומיים (%d) <u> הזמן לפי מזהה </ u>Invite by ID %1$s %2$s %1$s and %2$s "%1$s, " - האם אתה בטוח שברצונך להזמין את% s לצ\'אט זה\? + האם אתה בטוח שברצונך להזמין את%s לצ\'אט זה\? סיבה הסרת נידוי ממשתמש יאפשר לו להצטרף שוב לחדר. איסור על המשתמש יבעט בהם מחדר זה וימנע מהם להצטרף שוב. @@ -622,8 +615,6 @@ הודעות ישירות שיחה כלי אדמיניסטרציה - לפני% 1 $ s% 2 $ s - % 1 $ s עכשיו זמין אופליין אונליין @@ -649,7 +640,6 @@ בדיקה אחת או יותר נכשלו, אנא שלח דו\"ח שגיאה שיעזור לנו לחקור זאת. בדיקה אחת או יותר נכשלו, נסה הצעה/ות אלו לתיקון. אבחון בסיסי תקין. אם עדיין אינך מקבל התראות, אנא שלח דו\"ח שגיאה שיעזור לנו לחקור זאת. - פועל ... (% 1 $ d מתוך% 2 $ d) הרץ מבדקים אבחון לפתרון בעיות פותר בעיות התראות @@ -657,7 +647,7 @@ חשיבות ההודעה לפי אירוע הגדרות התראה מתקדמות וודא שלחצת על הקישור בהודעת הדוא\"ל ששלחנו אליך. - להסיר את% s\? + להסיר את%s\? מספרי טלפון לא הוספה כתובת דוא\"ל לחשבונך כתובות דוא\"ל @@ -677,7 +667,6 @@ זכויות יוצרים התראות צד שלישי תנאים והגבלות - גרסה s% גרסה הגדרות הודעות @@ -692,12 +681,6 @@ כל ההודעות כל ההודעות (קוליות) מחפש בתיקייה… - - נמצא% 1 $ s חדר עבור% 2 $ s - נמצא% 1 $ s חדר עבור% 2 $ s - נמצא% 1 $ s חדר עבור% 2 $ s - נמצא% 1 $ s חדר עבור% 2 $ s - d% חדר d% חדרים @@ -720,7 +703,7 @@ קבצים אנשים הודעות - האם אתה בטוח שברצונך להסיר את% s מהצ\'אט הזה\? + האם אתה בטוח שברצונך להסיר את%s מהצ\'אט הזה\? האם ברצונך לעזוב את החדר\? עזוב חדר diff --git a/vector/src/main/res/values-vi/strings.xml b/vector/src/main/res/values-vi/strings.xml index bfae929a57..5fd780f429 100644 --- a/vector/src/main/res/values-vi/strings.xml +++ b/vector/src/main/res/values-vi/strings.xml @@ -212,9 +212,9 @@ Cuộc gọi Element thất bại Đừng hỏi lại tôi Hãy thử dùng %s - Vui lòng yêu cầu quản trị viên của máy chủ nhà của bạn (%1$s) thiết lập một máy chủ TURN để các cuộc gọi có thể hoạt động [...]. + Vui lòng yêu cầu quản trị viên của máy chủ nhà của bạn (%1$s) thiết lập một máy chủ TURN để các cuộc gọi có thể hoạt động […]. \n -\nBạn cũng có thể thử dùng máy chủ công cộng ở %2$s, nhưng cách này sẽ không [...] bằng, và địa chỉ IP của bạn cũng sẽ được chia sẻ đến server đó. Bạn có thể quản lý việc này trong mục Cài đặt. +\nBạn cũng có thể thử dùng máy chủ công cộng ở %2$s, nhưng cách này sẽ không […] bằng, và địa chỉ IP của bạn cũng sẽ được chia sẻ đến server đó. Bạn có thể quản lý việc này trong mục Cài đặt. Cuộc gọi thất bại do thiết lập máy chủ sai Bạn có chắc bạn muốn bắt đầu một cuộc gọi video\? Bạn có chắc bạn muốn bắt đầu một cuộc gọi bằng giọng nói\? From 1a5291537d6850e62052ac8e4af33e76b93b9248 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Jan 2021 14:27:22 +0100 Subject: [PATCH 223/224] Correct support for Hebrew --- vector/src/main/res/values-he/strings.xml | 6 +- vector/src/main/res/values-iw/strings.xml | 1288 +++++++++++++++++++++ 2 files changed, 1291 insertions(+), 3 deletions(-) create mode 100644 vector/src/main/res/values-iw/strings.xml diff --git a/vector/src/main/res/values-he/strings.xml b/vector/src/main/res/values-he/strings.xml index 177548ea50..dbfd579ba6 100644 --- a/vector/src/main/res/values-he/strings.xml +++ b/vector/src/main/res/values-he/strings.xml @@ -124,9 +124,9 @@ ערכת נושא שחורה ערכת נושא כהה ערכת נושא בהירה - לטינית - ארה\"ב - אנגלית + Hebr + IL + iw משתמש %d %d משתמשים diff --git a/vector/src/main/res/values-iw/strings.xml b/vector/src/main/res/values-iw/strings.xml new file mode 100644 index 0000000000..dbfd579ba6 --- /dev/null +++ b/vector/src/main/res/values-iw/strings.xml @@ -0,0 +1,1288 @@ + + + התראות + כפתורי ניווט תחתונים + הצלחה + שגיאה + אזהרה + אישור + השבת + העתק ללוח הגזירים + הסר פרסום + הוסף + העתק + סגור + סמן כ\'נקרא\' + תגובה מהירה + היסטורי + סמן הכל כ\'נקרא\' + חיפוש כללי + שיחת וידאו + שיחה קולית + האם אתה בטוח שברצונך לצאת מחשבונך\? + יציאה מהחשבון + פעולות + יציאה + נתק + להסיר + לקבל + יְרִידָה + סקירה + להתעלם + לְהַפִּיל + בוצע + לדלג + לְקַבֵּל + לא מקוון + להזמין + לשלוח בכל מקרה + תתקשר בכל מקרה + שיחות ועידה אינן נתמכות בחדרים מוצפנים + הסרת היישומון נכשלה + הוספת היישומון נכשלה + מידע על מושב + אתה לא יכול להתקשר עם עצמך, לחכות שהמשתתפים יקבלו את ההזמנה + אינך יכול להתקשר עם עצמך + לא ניתן להתחיל להתקשר + הפגישות משתמשות במדיניות האבטחה וההרשאה של Jitsi. כל האנשים שנמצאים כעת בחדר יראו הזמנה להצטרף בזמן שהפגישה שלך מתרחשת. + התחל פגישת שמע + התחל פגישת וידאו + ועידה כבר בעיצומה! + אין לך הרשאה להתחיל שיחה + אין לך הרשאה להתחיל שיחה בחדר זה + אין לך הרשאה להתחיל שיחת ועידה + אין לך הרשאה להתחיל שיחת ועידה בחדר זה + אתה זקוק להרשאה כדי להזמין כדי להתחיל כנס בחדר זה + בגלל הרשאות חסרות, פעולה זו אינה אפשרית. + בגלל הרשאות חסרות, ייתכן שחלק מהתכונות חסרות … + לא יכול להתחיל את השיחה, נסה שוב מאוחר יותר + וידאו + קול + התחל לצ\'וטט + אתחול + השהה + לנגן + שיחה פעילה + דווח על תוכן + התנתק + לבטל + אין + שנה שם + מחק + צפה במקור המפוענח + צפה במקור הדף + קישור קבוע + העבר + מאוחר יותר + ניקוי + דבר + שתף + הורדה + צטט + הסר + שלח שוב + שלח + הישאר + עזיבה + שמירה + ביטול + אוקיי + טוען… + רישיונות צד ג \' + תאבד את הגישה להודעות המוצפנות שלך אלא אם כן תגבה את המפתחות לפני היציאה. + גבה + האם אתה בטוח\? + השתמש בגיבוי מפתח + מגבה מקשים … + אני לא רוצה את ההודעות המוצפנות שלי + גיבוי מפתח מאובטח צריך להיות פעיל בכל ההפעלות שלך כדי למנוע אובדן גישה להודעות המוצפנות שלך. + גיבוי המפתח מתבצע. אם תצא עכשיו תאבד את הגישה להודעות המוצפנות שלך. + אם תצא עכשיו, תאבד את ההודעות המוצפנות שלך + קישור למטריקס + או + פתיחה + כניסה + שחרר + גיבוי המפתחות לא הסתיים, אנא המתן … + אמת מושב + השתמש במפתח גיבוי + גיבוי מפתח + שלח מדבקה + פרטי קהילה + דיווח תקלות + הסטוריה + פרטי משתמש + הגדרות + חדר + הודעות + התראות שקטות + התראות רועשות + האזנה לאירועים + מסנכרן… + אתחול השירות + ערכת נושא Status.im + ערכת נושא שחורה + ערכת נושא כהה + ערכת נושא בהירה + Hebr + IL + iw + + משתמש %d + %d משתמשים + מעט + אחר + + אין חדרים ציבורים + אין חדרים + רשימת חדרים + חדרים + אין שיחות + אנשי קשר מטריקס בלבד + תיקיית האב של המשתמש + פנקס כתובות מקומי + שיחות + התראות מערכת + בעדיפות נמוכה + הזמנות + סנן שמות מבין רשימת הקהילות + סנן מבין רשימת החדרים + סנן מבין רשימת האנשים + סנן מהמועדפים + סנן שמות חדרים + קהילות + חדרים + לא הוגדר שרת זהות. + אין תוצאות נוספות + אין תוצאות + לא אפשרת לאלמנט לגשת לאנשי הקשר המקומיים שלך + האם אתה בטוח שברצונך להתחיל צ\'אט חדש עם %s\? + שלח קול + התחל שיחת וידאו + התחל שיחה קולית + התחל צ\'אט חדש + חיפוש + קישור לשרת הזיהוי + קישור לשרת הבית + יציאה + כניסה + צור חשבון + שם משתמש + הצטרף אל חדר + קרא + שלח פנימה + לא ניתן היה לשלוח את דוח הבאג (%s) + דוח הבאג נשלח בהצלחה + טלטול זעם כדי לדווח על באג + היישום התרסק בפעם האחרונה. האם ברצונך לפתוח את מסך דוח הקריסה\? + נראה שאתה מטלטל את הטלפון בתסכול. האם ברצונך לפתוח את מסך דוח הבאג\? + על מנת לאבחן בעיות, יומני הלקוח יישלחו עם דוח הבאג הזה. דוח באגים זה, כולל היומנים וצילום המסך, לא יהיה גלוי לציבור. אם אתה מעדיף לשלוח רק את הטקסט למעלה, בטל את הסימון: + תאר את הבעיה שלך כאן + אם אפשר, אנא כתוב את התיאור באנגלית. + אנא תאר את הבאג. מה עשית\? מה ציפית שיקרה\? מה באמת קרה\? + דווח על באג + שלח צילום מסך + שלח היסטוריית בקשות לשיתוף מפתח + שלח יומני תקלות + שלח יומנים + אין קבוצות + קהילות + הזמנה + שם משתמש זה כבר בשימוש + יותר מדי בקשות נשלחו + לא מכיל JSON חוקי + JSON פגום + אסימון הגישה שצוין לא זוהה + שם משתמש / סיסמא שגויים + המכשיר שלך משתמש בפרוטוקול אבטחה TLS מיושן, הפגיע להתקפה, למען ביטחונך לא תוכל להתחבר + שגיאת SSL. + שגיאת SSL: זהות העמית לא אומתה. + לא ניתן להגיע לשרת בית בכתובת אתר זו, אנא בדוק זאת + זו אינה כתובת שרת מטריקס חוקית + לא ניתן להגיע לכתובת אתר זו, אנא בדוק אותה + אנא הכנס כתובת תקינה + לא ניתן להירשם: כשל בבעלות על דוא\"ל + לא ניתן להירשם + לא ניתן להירשם: שגיאת רשת + לא מצליח להתחבר + לא ניתן להתחבר: שגיאת רשת + כתובת האתר חייבת להתחיל ב- http [s]: // + אנא עיין וקבל את המדיניות של שרת בית זה: + הסיסמה שלך אופסה. +\n +\nהוצאת מכל ההפעלות ולא תקבל עוד התראות דחיפה. כדי להפעיל מחדש התראות, התחבר מחדש בכל מכשיר. + אימות כתובת הדוא\"ל נכשל: ודא שלחצת על הקישור בדוא\"ל + דוא\"ל נשלח אל%s. לאחר שתעקוב אחר הקישור שהוא מכיל, לחץ למטה. + יש להזין סיסמה חדשה. + יש להזין את כתובת הדוא\"ל המקושרת לחשבונך. + כדי לאפס את הסיסמה שלך, הזן את כתובת הדוא\"ל המקושרת לחשבונך: + אימתתי את כתובת הדוא\"ל שלי + שרת זיהוי: + שרת הבית: + שם משתמש כבר נמצא בשימוש + שרת בית זה רוצה לוודא שאתה לא רובוט + הרשמה באמצעות דוא\"ל ומספר טלפון בבת אחת עדיין אינה נתמכת עד להתקנת ה- API. רק מספר הטלפון ייקח בחשבון. +\n +\nתוכל להוסיף את הדוא\"ל שלך לפרופיל שלך בהגדרות. + אנא בדוק את הדוא\"ל שלך כדי להמשיך בהרשמה + השתמש באפשרויות שרת מותאמות אישית (מתקדם) + שכחת סיסמה\? + סיסמא אינה תואמת לקודמתה + מטבע אינו חוקי + כתובת דוא\"ל או מספר טלפון חסרים + מספר טלפון חסר + כתובת דוא\"ל חסרה + מספר הטלפון הזה כבר קיים ומעודכן במערכת. + כתובת הדוא\"ל הזו כבר קיימת ומוגדרת במערכת. + זה אינו נראה כמספר טלפון חוקי + זה לא נראה כמו כתובת דוא\"ל חוקית + סיסמה חסרה + סיסמה קצרה מדי (נדרש לפחות 6 תווים) + שמות משתמשים עשויים להכיל רק אותיות, מספרים, נקודות, מקפים וקו תחתון + שם משתמש ו/או סיסמה לא נכונים + אשר את סיסמתך החדשה + חזור על הסיסמה + מספר טלפון (אופציונלי) + מספר טלפון + כתובת דוא\"ל (אופציונלי) + כתובת דוא\"ל + הגדר דוא\"ל לשחזור חשבון. השתמש באימייל או בטלפון מאוחרים יותר כדי שאפשר יהיה לגלות אותו על ידי אנשים שמכירים אותך. + הגדר דוא\"ל לשחזור חשבון. השתמש באימייל או בטלפון מאוחרים יותר כדי שאפשר יהיה לגלות אותו על ידי אנשים שמכירים אותך. + הגדר טלפון, ואחר כך יהיה ניתן לגלות אותו על ידי אנשים שמכירים אותך. + הגדר דוא\"ל לשחזור חשבון, ומאוחר יותר כך שניתן יהיה לגלות אותו על ידי אנשים שמכירים אותך. + שם משתמש + סיסמה חדשה + סיסמה + מייל או שם משתמש + חזור למסך כניסה + שלח מייל איפוס + דלג + הגש + צור חשבון + היכנס באמצעות כניסה יחידה + היכנס + מצטערים, לא נמצאה יישום חיצוני להשלמת פעולה זו. + המשך עם… + כרגע אין לך חבילות מדבקה מופעלות. +\n +\nלהוסיף כמה עכשיו\? + צלם סרטון + צלם תמונה + צלם תמונה או סרטון + שלח סטיקר + שלח קבצים + הפעל מצב HD + כבה מצב HD + אחורה + קדימה + החלף בין מצלמה + אוזניות אלחוטיות + אוזניות + רמקול + טלפון + בחר מכשיר סאונד + נכשל החיבור בזמן אמת. +\nאנא בקש ממנהל שרת הבית שלך להגדיר שרת TURN על מנת שהשיחות יעבדו בצורה אמינה. + שיחת האלמנט נכשלה + אל תשאל אותי שוב + נסה להשתמש ב-%s + השיחה נכשלה עקב שרת שהוגדר כהלכה + האם אתה בטוח שברצונך להתחיל שיחת וידאו\? + האם אתה בטוח שברצונך להתחיל שיחה קולית\? + צ\'ט חדש + הוסף שרת זהות בהגדרות שלך כדי לבצע פעולה זו. + זו תצוגה מקדימה של החדר הזה. אינטראקציות בחדר הושבתו. + חדר + אתה מנסה לגשת ל-%s. האם תרצה להצטרף על מנת להשתתף בדיון\? + הזמנה זו נשלחה אל%s, שאינה משויכת לחשבון זה. +\nייתכן שתרצה להתחבר עם חשבון אחר, או להוסיף דוא\"ל זה לחשבונך. + הוזמנת להצטרף לחדר זה על ידי%s + קפיצה להודעה הראשונה שלא נקראה. + מסנכרן… + פתח כותרת + חברי רשימה + דחייה + תצוגה מקדימה + הצטרף + הסר + המשך + לא!! + כן! + שמור להורדות\? + נשמר + אפשר הרשאה לגשת לאנשי הקשר שלך. + כדי לסרוק קוד QR, עליך לאפשר גישה למצלמה. + מצטער. הפעולה לא בוצעה בגלל הרשאות חסרות + אלמנט יכול לבדוק את פנקס הכתובות שלך כדי למצוא משתמשי מטריקס אחרים על סמך מספרי הדוא\"ל והטלפון שלהם. +\n +\nהאם אתה מסכים לשתף את פנקס הכתובות שלך למטרה זו\? + אלמנט יכול לבדוק את פנקס הכתובות שלך כדי למצוא משתמשי מטריקס אחרים על סמך מספרי הדוא\"ל והטלפון שלהם. אם אתה מסכים לשתף את פנקס הכתובות שלך למטרה זו, אנא הגש גישה בחלון הקופץ הבא. + אלמנט זקוק להרשאה כדי לגשת למצלמה ולמיקרופון שלך כדי לבצע שיחות וידאו. +\n +\nאנא אפשר גישה בחלונות הקופצים הבאים כדי להיות מסוגל לבצע את השיחה. + " +\n +\nאנא אפשר גישה בחלון הקופץ הבא כדי שתוכל לבצע את השיחה." + אלמנט זקוק להרשאה כדי לגשת למיקרופון שלך כדי לבצע שיחות שמע. + " +\n +\nאנא אפשר גישה בחלון הקופץ הבא כדי שתוכל לבצע את השיחה." + אלמנט זקוק להרשאה כדי לגשת למצלמה שלך כדי לצלם תמונות ושיחות וידאו. + אלמנט זקוק להרשאה כדי לגשת לספריית התמונות והווידיאו שלך כדי לשלוח ולשמור קבצים מצורפים. +\n +\nאנא אפשר גישה בחלון הקופץ הבא כדי שתוכל לשלוח קבצים מהטלפון שלך. + מידע + לא ניתן להקליט וידאו + צלם תמונה או סרטון + השיחה נענתה במקום אחר + לא ניתן לאתחל את המצלמה + חיבור המדיה נכשל + הצד המרוחק לא הצליח להרים. + חזור לשיחה + שיחה פעילה (%s) + שיחת וידאו מתבצעת … + במהלך התקשרות… + שיחה קולית נכנסת + שיחת וידאו נכנסת + שיחה נכנסת + מתקשר… + שיחה הסתיימה + שיחה מתחברת … + שיחה מחוברת + שִׂיחָה + בחר רינגטון לשיחות: + רינגטון שיחה נכנסת + ישתמש ב-%s כסיוע כאשר השרת הביתי שלך אינו מציע כזה (כתובת ה- IP שלך תשותף במהלך שיחה) + אפשר שרת עזרה לשיחות + השתמש ברינגטון ברירת המחדל של אלמנט לשיחות נכנסות + בקש אישור לפני שמתחילים בשיחה + מנע שיחה מקרית + שיחות + נושא החדר + שם חדר + היום + אתמול + %1$dm %2$ds + % d s + האם לבטל את ההעלאה\? + האם לבטל את ההורדה\? + קטן + בינוני + גדול + מקור + שלח כ + + שינוי בפרט חברות + שינוי בפרטי חברות + שינוי בפרטי חברות + שינוי בפרטי חברות + + רשימת קבוצות + קרא את רשימת הקבלות + הפעל את Element במכשיר אחר שיכול לפענח את ההודעה כדי שיוכל לשלוח את המפתחות להפעלה זו. + הבקשה נשלחה + בקשת המפתח נשלחה. + בקש מחדש מפתחות הצפנה מהפעלות האחרות שלך. + בטל הכל + שלח מחדש הכל + הודעות לא נשלחו בגלל הימצאות פעילויות לא ידועות. %1$s או %2$s עכשיו\? + הודעות לא נשלחו. %1$s או %2$s עכשיו\? + הקישוריות לשרת אבדה. + שלח תשובה (לא מוצפן) … + יעדי התראות + ניהול מפתחות קריפטוגרפיה + קריפטוגרפיה + השתמש במנהל שילוב לניהול בוטים, גשרים, ווידג\'טים וחבילות מדבקות. +\nמנהלי אינטגרציה מקבלים נתוני תצורה ויכולים לשנות ווידג\'טים, לשלוח הזמנות לחדר ולהגדיר רמות כוח מטעמכם. + אינטגרציות + מתקדם + אחר + משתמשים שמתעלמים מהם + התראות + הגדרות משתמש + נקה מטמון מדיה + נקה את זיכרון המטמון + שמור על מדיה + מדיניות הפרטיות + זכויות יוצרים + התראות צד שלישי + תנאים והגבלות + גרסת olm + גִרְסָה + + % d שנייה + % d שניות + % d שניות + % d שניות + + עיכוב בין כל סינכרון + %s +\nהסנכרון עשוי להידחות בהתאם למשאבים (סוללה) או מצב ההתקן (שינה). + מרווח סינכרון מועדף + פסק-זמן לבקשה לסנכרון + אפשר סנכרון רקע + החל באתחול + עדכון ההגדרות נכשל. + לא תקבל הודעה על הודעות נכנסות כאשר האפליקציה ברקע. + אין סנכרון רקע + אלמנט יסונכרן ברקע מעת לעת בזמן מדויק (ניתן להגדרה). +\nזה ישפיע על השימוש ברדיו ובסוללה, תוצג הודעה קבועה לפיה אלמנט מאזין לאירועים. + מותאם לזמן אמת + אלמנט יסונכרן ברקע באופן שישמור על המשאבים המוגבלים של המכשיר (סוללה). +\nבהתאם למצב משאבי המכשיר שלך, ייתכן שהסנכרון יידחה על ידי מערכת ההפעלה. + מותאם לסוללה + מצב סנכרון רקע + סנכרון רקע + הודעות שנשלחו על ידי בוט + הזמנות לשיחות + כשאני מוזמן לחדר + הודעות בצ\'אטים קבוצתיים + הודעות בצ\'אטים אחד-על-אחד + הודעות שמכילות את שם המשתמש שלי + הודעות שמכילות את שם התצוגה שלי + בחר צבע LED, רטט, צליל … + הגדר התראות שקטות + הגדר התראות על שיחות + הגדר תצורה של התראות רועשות + הדלק את המסך למשך 3 שניות + אפשר התראות עבור מושב זה + אפשר התראות עבור חשבון זה + צליל התראה + • התראות <b> לא יציגו את תוכן ההודעה </ b>not show message content + • התראות מכילות <b> נתוני ליבה והודעות </ b>meta and message data + • תוכן ההודעה של ההודעה <b> ממוקם בצורה מאובטחת ישירות משרת הבית של מטריקס </ b>located securely direct from the Matrix homeserver + • התראות מכילות רק נתוני ליבה + • התראות נשלחות באמצעות Firebase Cloud Messaging + היישומים <b> לא </ b> צריכים להתחבר ל- HomeServer ברקע, זה אמור להפחית את השימוש בסוללהnot need to connect to the HomeServer in the background, it should reduce battery usage + האפליקציה זקוקה לאישורך כדי לפעול ברקע + פרטיות מצומצמת + רגיל + התעלם מאופטימיזציה + אם משתמש משאיר מכשיר מחובר לחשמל ויציב לתקופה מסוימת, כשהמסך כבוי, המכשיר עובר למצב Doze. זה מונע מאפליקציות גישה לרשת ומגדיר את העבודות, הסנכרונים וההתראות הסטנדרטיות שלהם. + אלמנט אינו מושפע מתהליך מיטוב הסוללה. + אופטימיזציה של הסוללה + השבת הגבלות + מגבלות רקע מופעלות עבור Element. +\nהעבודה שהאפליקציה מנסה לעשות תוגבל באגרסיביות בזמן שהיא ברקע, וזה עלול להשפיע על ההודעות. +\n%1$s + מגבלות רקע מושבתות עבור Element. יש להריץ בדיקה זו באמצעות נתונים ניידים (ללא WIFI). +\n%1$s + בדוק מגבלות רקע + הפעל את התחלה לאחר אתחול + השירות לא יופעל עם הפעלת המכשיר מחדש, לא תקבל התראות עד שאלמנט ייפתח לפחות פעם אחת. + השירות יתחיל עם הפעלת המכשיר מחדש. + הפעל לאחר אתחול + השירות נכשל מלעלות מחדש + השירות נסגר והופעל מחדש אוטומטית. + הפעלה מחדש אוטומטית לשירות ההתראות + החל שירות + שירות ההתראות אינו פועל. +\nנסה להפעיל מחדש את היישום. + שירות ההתראות פועל. + שירות התראות + ההודעה נלחצה! + אנא לחץ על ההודעה. אם אינך רואה את ההודעה, אנא בדוק את הגדרות המערכת. + תצוגת התראות + אתה צופה בהודעה! לחץ עלי! + קבלת הדחיפה נכשלה. הפתרון יכול להיות התקנה מחדש של היישום. + בדיקת שליחה בדחיפה (PUSH) + היישום מקבל PUSH + היישום ממתין ל- PUSH + נכשל רישום אסימון FCM ל- HomeServer: +\n%1$s + אסימון FCM נרשם בהצלחה ל- HomeServer. + רישום אסימונים + הוסף חשבון + [%1$s] +\nשגיאה זו אינה בשליטה על אלמנט. אין חשבון Google בטלפון. אנא פתח את מנהל החשבון והוסף חשבון Google. + [%1$s] +\nשגיאה זו אינה בשליטה על אלמנט. זה יכול להתרחש מכמה סיבות. אולי זה יעבוד אם תנסה שוב מאוחר יותר, תוכל גם לבדוק ששירות Google Play אינו מוגבל בשימוש נתונים בהגדרות המערכת, או ששעון המכשיר שלך תקין, או שזה יכול לקרות ב- ROM מותאם אישית. + [%1$s] +\nשגיאה זו איננה בשליטה על Element ולפי גוגל, שגיאה זו מצביעה על כך שלמכשיר יש יותר מדי אפליקציות הרשומות ב- FCM. השגיאה מתרחשת רק במקרים שבהם ישנם מספרים קיצוניים של אפליקציות, כך שהיא לא אמורה להשפיע על המשתמש הממוצע. + נכשל באחזור אסימון FCM: +\n%1$s + אסימון FCM אוחזר בהצלחה: +\n%1$s + אסימון Firebase + תקן שירותי Google Play + אלמנט משתמש בשירותי Google Play כדי להעביר הודעות פוש אך נראה שהוא אינו מוגדר כהלכה: +\n%1$s + ה- APK של שירותי Google Play זמין ומעודכן. + בדיקת שירותי הפעלה + בדוק בהגדרות + טעינת הכללים המותאמים אישית נכשלה, אנא נסה שוב. + חדרים + אין תוצאות + סנן משתמשים מודרים + סנן חברים מהחדר + חפש + בטל הורדה + בטל העלאה + האם ברצונך להסתיר את כל ההודעות ממשתמש זה\? +\nשים לב שפעולה זו תפעיל מחדש את האפליקציה והיא עשויה להימשך זמן מה. + סיבה לדיווח על תוכן זה + הצטרף + מוזמן + תעודת זהות שגויה. צריכה להיות כתובת דוא\"ל או מזהה מטריצה כמו \'@localpart: domain\' + + % d נבחר + % d נבחרים + % d נבחרים + % d נבחרים + + הגדרות + קבצים + אנשים + פרטי החדר + קבל את האישור רק אם מנהל השרת פרסם טביעת אצבע התואמת את זו שלמעלה. + האישור השתנה מאישור מהימן בעבר לאיש מהימן. ייתכן שהשרת חידש את האישור שלו. פנה למנהל השרת לקבלת טביעת האצבע הצפויה. + האישור השתנה מאישור שהטלפון שלך אמין עליו. זה מאוד לא שגרתי. מומלץ לא לקבל את האישור החדש הזה. + אם מנהל השרת אמר שזה צפוי, ודא שטביעת האצבע שלמטה תואמת את טביעת האצבע שמספקת אותם. + יכול להיות שמישהו מיירט את התעבורה שלך בזדון, או שהטלפון שלך לא סומך על האישור שמספק השרת המרוחק. + לא ניתן לאמת את זהות השרת המרוחק. + טביעת אצבע (%s): + התעלם + יציאה + אל תתן אמון + אמון + + הודעה חדשה + הודעות חדשות + הודעות חדשות + הודעות חדשות + + אין לך הרשאה לפרסם בחדר זה + הקובץ לא נמצא + מחק הודעות שלא נשלחו + שלח שוב הודעות שלא נשלחו + שלח תשובה מוצפנת … + שלח הודעה (לא מוצפן) … + שלח הודעה מוצפנת … + %1$s &%2$s ואחרים מקלידים … + %1$s &%2$s מקלידים … + %s מקליד … + חפש + אימייל או מזהה מטריקס + אנא הזן כתובת דוא\"ל אחת או יותר או מזהה מטריקס + הזמן משתמש לפי מזהה + משתמשי מטריקס בלבד + אנשי קשר מקומיים (%d) + <u> הזמן לפי מזהה </ u>Invite by ID + %1$s %2$s + %1$s and %2$s + "%1$s, " + האם אתה בטוח שברצונך להזמין את%s לצ\'אט זה\? + סיבה + הסרת נידוי ממשתמש יאפשר לו להצטרף שוב לחדר. + איסור על המשתמש יבעט בהם מחדר זה וימנע מהם להצטרף שוב. + הסר נידוי ממשתמש + סיבות לנידוי + נדה משתמש + משתמש מעיף יסיר אותם מחדר זה. +\n +\nכדי למנוע מהם להצטרף שוב, עליך לאסור אותם במקום זאת. + סיבות להעפה + העף משתמש + האם אתה בטוח שברצונך לבטל את ההזמנה עבור משתמש זה\? + בטל הזמנה + הסרת התעלמות + ביטול חתימת משתמש זה יציג את כל ההודעות מהם שוב. + הסרת התעלמות ממשתמש + התעלם + התעלמות ממשתמש זה תסיר את ההודעות שלו מחדרים שאתה משתף. +\n +\nאתה יכול להפוך פעולה זו בכל עת בהגדרות הכלליות. + התעלם ממשתמש + לְהוֹרִיד בְּדַרגָה + לא תוכל לבטל את השינוי הזה מכיוון שאתה מוריד את עצמך בדרגה, אם אתה המשתמש המיועד האחרון בחדר, אי אפשר יהיה להחזיר לו הרשאות. + להוריד את עצמך\? + לא תוכל לבטל את השינוי הזה מכיוון שאתה מקדם את המשתמש לאותה רמת כוח כמוך. +\nהאם אתה בטוח\? + הצג רשימת מושבים + אזכר + מזהה משתמש, שם או דוא\"ל + הפוך למנהל + הפוך למנחה + אפס למשתמש רגיל + העף + הסרת התעלמות + התעלם + הסר מחדר זה + עזוב חדר זה + בטל הזמנה + הזמן + מושבים + הודעות ישירות + שיחה + כלי אדמיניסטרציה + זמין + אופליין + אונליין + צור + חלק מההתראות מושבתות בהגדרות המותאמות אישית שלך. + שים לב שחלק מסוגי ההודעות מוגדרים כשתיקים (יפיקו התראה ללא צליל). + הגדרות מותאמות אישית. + אפשר + התראות אינן מופעלות עבור הפעלה זו. +\nאנא בדוק את הגדרות האלמנט. + התראות מופעלות להפעלה זו. + הגדרות מושב. + אפשר + התראות מושבתות עבור חשבונך. +\nאנא בדוק את הגדרות החשבון. + התראות מופעלות עבור חשבונך. + הגדרות חשבון. + פתח את ההגדרות + התראות מושבתות בהגדרות המערכת. +\nאנא בדוק את הגדרות המערכת. + התראות מופעלות בהגדרות המערכת. + הגדרות מערכת. + בדיקה אחת או יותר נכשלו, אנא שלח דו\"ח שגיאה שיעזור לנו לחקור זאת. + בדיקה אחת או יותר נכשלו, נסה הצעה/ות אלו לתיקון. + אבחון בסיסי תקין. אם עדיין אינך מקבל התראות, אנא שלח דו\"ח שגיאה שיעזור לנו לחקור זאת. + הרץ מבדקים + אבחון לפתרון בעיות + פותר בעיות התראות + פרטיות הודעות + חשיבות ההודעה לפי אירוע + הגדרות התראה מתקדמות + וודא שלחצת על הקישור בהודעת הדוא\"ל ששלחנו אליך. + להסיר את%s\? + מספרי טלפון + לא הוספה כתובת דוא\"ל לחשבונך + כתובות דוא\"ל + נדרש אימות + אינך יכול לעשות זאת ממכשיר נייד + אשר את סיסמתך + הצג את פרטי היישום בהגדרות המערכת. + מידע על האפליקציה + הוסף מספר טלפון + לא הוסף מספר טלפון לחשבונך + מספר טלפון + הוסף כתובת דוא\"ל + כתובת דוא\"ל + שם תצוגה + תמונת פרופיל + מדיניות הפרטיות + זכויות יוצרים + התראות צד שלישי + תנאים והגבלות + גרסה + הגדרות + הודעות + הוסף למסך הבית + שכח + עזוב את השיחה + צ\'אט ישיר + בטל עדיפות + מועדף + השתק + אזכורים בלבד + כל ההודעות + כל ההודעות (קוליות) + מחפש בתיקייה… + + d% חדר + d% חדרים + d% חדרים + d% חדרים + + חפש בתיקיות + הקלד מזהה חדר או כינוי לחדר + הצטרף לחדר + הצטרף לחדר + צור חדר + התחלת שיחת צ\'אט + הזמנות + עדיפות נמוכה + חדרים + מועדפים + תיקייה ראשית + הצטרף + עדיין אין תמיכה בחיפוש בחדרים מוצפנים. + קבצים + אנשים + הודעות + האם אתה בטוח שברצונך להסיר את%s מהצ\'אט הזה\? + האם ברצונך לעזוב את החדר\? + עזוב חדר + + %dd + %dd + %dd + %dd + + + %dh + %dh + %dh + %dh + + + %dm + %dm + %dm + %dm + + + %ds + %ds + %ds + %ds + + חבר אחד + + חבר + חברים + חברים + חברים + + + חבר פעיל + חברים פעילים + חברים פעילים + חברים פעילים + + הוסף חבר + התחל אימות + מושב לא מאומת מבקש מפתחות הצפנה. +\nשם מושב: %1$s +\nנראה לאחרונה: %2$s +\nאם לא נכנסת למפגש אחר, התעלם מבקשה זו. + ההפעלה \'%s\' לא מאומתת מבקשת מפתחות הצפנה. + מושב חדש מבקש מפתחות הצפנה. +\nשם מושב: %1$s +\nנראה לאחרונה: %2$s +\nאם לא נכנסת למפגש אחר, התעלם מבקשה זו. + הוספת מושב חדש \'%s\', המבקש מפתחות הצפנה. + כדי להמשיך עליך לקבל את תנאי השירות הזה. + אפשרות זו מחייבת יישום צד שלישי להקליט את ההודעות. + שלח הודעות קוליות + השתמש במקש הזנת המקלדת כדי לשלוח הודעה + הפעל את מצלמת המערכת במקום את מסך המצלמה המותאם אישית. + השתמש במצלמה מקומית + אין יישומונים פעילים + נהל אינטגרציות + הוסף אפליקציות מטריקס + לא הוגדר מנהל אינטגרציה. + פרמטר אינו חוקי. + פרמטר חובה חסר. + החדר %s אינו גלוי. + חסר זהות משתמש בבקשה. + חסר מספר זהות חדר בבקשה. + אין לך אישור לעשות זאת בחדר זה. + אתה לא בחדר הזה. + רמת הרשאה חייבת להיות חיובית שלמה. + שליחת הבקשה נכשלה. + לא ניתן ליצור יישומון. + קרא מדיה מוגנת DRM + השתמש במיקרופון + השתמש במצלמה + חסום הכל + אפשר + יישומון זה רוצה להשתמש במשאבים הבאים: + מצטערים, שיחות ועידה עם Jitsi אינן נתמכות במכשירים ישנים (מכשירים עם מערכת הפעלה אנדרואיד מתחת ל -5.0) + מזהה חדר + מזהה ישומון + ערכת הנושא שלכם + מזהה המשתמש שלך + כתובת האתר של הדמות שלך + שם התצוגה שלך + בטל גישה עבורי + פתח בדפדפן + טען יישומון מחדש + השימוש בו עשוי לשתף נתונים עם %s: + השימוש בו עשוי להגדיר קובצי cookie ולשתף נתונים עם %s: + ישומון זה התווסף על ידי: + טען ישומון + ישומון + ישומונים פעילים + צפה + + %d יישומון פעיל + %d ישומונים פעילים + %d ישומונים פעילים + %d ישומונים אחרים פעילים + + האם אתה בטוח שברצונך למחוק את היישומון מחדר זה\? + צור שיחות ועידה עם jitsi + יצירת היישומון נכשלה + אתה זקוק להרשאה כדי לנהל יישומונים בחדר זה + ענק + הכי גדול + גדול יותר + גדול + רגיל + קטן + זעיר + גודל גופן + חפש היסטורי + %1$s: %2$s %3$s + %1$s:%2$s + ** השליחה נכשלה - אנא פתח את החדר + אני + הזמנות חדשות + הודעות חדשות + חדר + מאורע חדש + %1$s ו %2$s + %1$s ב %2$s ו %3$s + %1$s ב %2$s + + התראה %1$s: %2$d + התראות %1$s: %2$d + התראות מועטות %1$s: %2$d + התראות אחרות %1$s: %2$d + + + הודעה %1$s: %2$d + הודעות %1$s: %2$d + הודעות מעטות %1$s: %2$d + הודעות אחרות %1$s: %2$d + + + %d הזמנה + %d הזמנות + %d הזמנות מעטות + %d הזמנות אחרות + + + %d חדר + %d חדרים + %d חדרים מועטים + %d חדרים אחרים + + + %d הודעת התראה שלא נקראה + %d הודעות התראה שלא נקראו + %d הודעות התראה מעטות שלא נקראו + %d הודעות התראה אחרות שלא נקראו + + + הודעת התראה %d שלא נקראה + %d הודעות התראה שלא נקראו + %d הודעות התראה מעטות שלא נקראו + %d הודעות התראה אחרות שלא נקראו + + הקלד פה… + כל החדרים המקומיים %s + כל החדרים בשרת %s + כתובת אתר של שרת בית + הקלד שרת בית כדי לרשום ממנו חדרים ציבוריים + ייתכן שהשרת אינו זמין או עומס יתר + בחר מדריך חדרים + חדר זה מכיל פעילויות לא ידועות שלא אומתו. +\nהמשמעות היא שאין ערובה לכך שההפעלות שייכות למשתמשים שהם טוענים להם. +\nאנו ממליצים שתעבור את תהליך האימות של כל מפגש לפני שתמשיך, אך תוכל לשלוח שוב את ההודעה מבלי לאמת אם אתה מעדיף. +\n +\nהפעלות לא ידועות: + החדר מכיל הפעלות לא ידועות + אני מאשר שהמפתחות תואמים + אם הם לא תואמים, אבטחת התקשורת שלך עלולה להיפגע. + אשרו על ידי השוואה בין הדברים הבאים להגדרות המשתמש בפגישה האחרת שלכם: + אמת מושב + הסר מרשימה שחורה + רשימה שחורה + הסר אימות + אמת + ללא + IP לא ידוע + מושב לא ידוע + ברשימה שחורה + מאומת + לא תקין + + מפתח %1$d/%2$d מיובא בהצלחה. + מפתחות %1$d/%2$d יובאו בהצלחה. + מפתחות %1$d/%2$d מעטים יובאו בהצלחה. + מפתחות %1$d/%2$d אחרים יובאו בהצלחה. + + לעולם אל תשלח הודעות מוצפנות להפעלות לא מאומתות מהפגישה זו. + הצפן למפגשים מאומתים בלבד + יבא + ייבא את המפתחות מקובץ מקומי + ייבא מפתחות לחדר + ייבא מפתחות לחדר E2E + נהל גיבוי מפתח + שחזור הודעות מוצפנות + מפתחות יוצאו בהצלחה + מקשי החדר E2E נשמרו ב- \'%s\'. +\n +\nאזהרה: קובץ זה עשוי להימחק אם הסרת ההתקנה של היישום. + אנא צור משפט סיסמה להצפנת המפתחות המיוצאים. יהיה עליך להזין את אותו ביטוי סיסמה כדי שתוכל לייבא את המפתחות. + יצא + יצא מפתחות לקובץ מקומי + יצא מפתחות חדר + ייצא מפתחות חדר E2E + טביעת אצבע Ed25519 + אימות + מזהה מפתח + מזהה מושב + שם ציבורי + השם הציבורי של הפגישה גלוי לאנשים שאיתם אתה מתקשר + שם ציבורי (גלוי לאנשים שאיתם אתה מתקשר) + שם ציבורי + מידע על מושב השולח + שגיאת פענוח + מזהה מושב + מזהה משתמש + אַלגוֹרִיתְם + תביעת מפתח טביעת אצבע של Ed25519 + מפתח זהות Curve25519 + מידע על האירוע + מידע על הצפנה מקצה לקצה + %s ניסתה לטעון נקודה מסוימת בציר הזמן של החדר הזה אך לא הצליחה למצוא אותה. + ערכת נושא + מַדרִיך + אפשר הצפנה +\n(אזהרה: לא ניתן להשבית שוב!) + הצפנה מושבתת בחדר זה. + הצפנה מופעלת בחדר זה. + העתק כתובת חדר + העתק מזהה חדר + ביטול ההגדרה ככתובת הראשית + הגדר ככתובת ראשית + אזהרות כתובת עיקריות + לא תהיה לך כתובת ראשית שצוינה לחדר זה. + \'%s\' אינו פורמט חוקי לכינוי + פורמט כינוי לא חוקי + \'%s\' אינו מזהה קהילה חוקי + מזהה קהילה לא חוקי + מזהה קהילה חדש (למשל + foo: matrix.org) + חדר זה אינו מגלה כישרון בקרב קהילות כלשהן + כתובת חדשה (למשל #foo: matrix.org) + לחדר זה אין כתובות מקומיות + לעולם אל תשלח הודעות מוצפנות להפעלות לא מאומתות בחדר זה מהפגישה זו. + הצפן לביקורים מאומתים בלבד + עליך להתנתק כדי שתוכל לאפשר את ההצפנה. + הצפנה מקצה לקצה פעילה + הצפנה מקצה לקצה + אלה תכונות ניסיוניות שעשויות להישבר בדרכים לא צפויות. השתמש בזהירות. + מעבדות + כתובות + תעודת הזהות הפנימית של החדר הזה + מתקדם + משתמשים אסורים + כל מי שמכיר את הקישור לחדר, כולל אורחים + כל מי שמכיר את הקישור לחדר, מלבד האורחים + רק אנשים שהוזמנו + כדי לקשר לחדר חייבת להיות כתובת. + חברים בלבד (מאז שהצטרפו) + חברים בלבד (מאז שהוזמנו) + חברים בלבד (מאז נקודת הזמן לבחירת אפשרות זו) + כל אדם + לא ניתן לאחזר את הראות הנוכחית של ספריית החדרים (%1$s). + לפרסם את החדר הזה לציבור במדריך החדרים של %1$s\? + בטל את הפרסום של כתובת זו + פרסם כתובת זו + הוסף כתובת מקומית + לחדר זה אין כתובות מקומיות + הגדר כתובות לחדר זה כדי שמשתמשים יוכלו למצוא את החדר הזה דרך שרת הבית שלך (%1$s) + כתובות מקומיות + כתובת שפורסמה חדשה (למשל alias:server#) + עדיין אין כתובות שפורסמו. + עדיין אין כתובות שפורסמו, הוסף כתובת למטה. + פרסם חדר זה כציבורי ברשימת החדרים של \"%1$s\"\? + מחק את הכתובת \"%1$s\"\? + הסר פרסום של הכתובת \"%1$s\"\? + פרסם + פרסם כתובת חדשה באופן ידני + כתובות אחרות שפורסמו: + כתובת ראשית + זו הכתובת העיקרית + כל אחד מכל שרת יכול להשתמש בכתובות שפורסמו כדי להצטרף לחדר שלך. כדי לפרסם כתובת, תחילה יש להגדיר אותה ככתובת מקומית. + כתובות שפורסמו + כתובות חדרים + ראה וניהול כתובות של חדר זה, והנראות שלו בספריית החדרים. + כתובות החדר + גישה לחדר + מי יכול לגשת לחדר הזה\? + שינויים במי שיכול לקרוא היסטוריה יחולו רק על הודעות עתידיות בחדר זה. נראות ההיסטוריה הקיימת לא תשתנה. + מי יכול לקרוא היסטוריה\? + הקריאה בהיסטוריה של החדרים + גישה לחדר + התראות + רשום חדר זה ברשימת החדרים + כניסה ונראות + ללא + עדיפות נמוכה + מועדפים + תוייג כ-: + תגית חדר + נושא + שם חדר + תמונת חדר + לעד + חודש 1 + שבוע 1 + 3 ימים + אינכם חברים בשום קהילה. + כשרון + השמע צליל תריס + בחרו + מקור מדיה ברירת מחדל + בחרו + דחיסת ברירת מחדל + מדיה + מידע נוסף: %s + אירעה שגיאה במהלך אימות מספר הטלפון שלך. + קוד + שגיאה בעת אימות מספר הטלפון שלך + הזן קוד הפעלה + שלחנו SMS עם קוד הפעלה. אנא הזן קוד זה למטה. + אימות טלפון + מספר טלפון לא חוקי עבור המדינה שנבחרה + מספר טלפון + בבקשה בחרו מדינה + מדינה + בחר\\י מדינה + האם אתה בטוח שברצונך להסיר את %1$s %2$s \? + האם אתה בטוח שברצונך להסיר את יעד ההודעות הזה\? + נהל מיילים ומספרי טלפון המקושרים לחשבון מטריקס שלך + דוא\"ל ומספר טלפון + סיסמאות לא תואמות + הצג את כל ההודעות מ- %s\? +\n +\nשים לב שפעולה זו תפעיל מחדש את האפליקציה והיא עשויה להימשך זמן מה. + הסיסמה שלכם עודכנה + הסיסמה אינה תקינה + עדכון הסיסמה נכשל + עדכון סיסמה + אישור סיסמה חדשה + סיסמה חדשה + סיסמה נוכחית + שינוי סיסמה + סיסמה + הסתיים + שמור על מפתח התאוששות שלך במקום כלשהו מאובטח מאוד, כמו מנהל סיסמאות (או כספת) + מפתח השחזור שלך הוא רשת ביטחון - אתה יכול להשתמש בו כדי להחזיר את הגישה להודעות המוצפנות שלך אם תשכח את משפט הסיסמה שלך. +\nשמור על מפתח התאוששות שלך במקום כלשהו מאובטח מאוד, כמו מנהל סיסמאות (או כספת) + המפתחות שלך מגובים. + הצלחה! + (מתקדם) הגדר עם מפתח השחזור + לחלופין, אבטח את הגיבוי שלך באמצעות מפתח שחזור ושמור אותו במקום בטוח. + יוצר גיבוי + הגדר ביטוי + אנו נאחסן עותק מוצפן של המפתחות שלך בשרת הבית שלך. הגן על הגיבוי שלך באמצעות משפט סיסמה כדי לשמור על אבטחתו. +\n +\nליתר ביטחון, זה צריך להיות שונה מסיסמת החשבון שלך. + אבטח את הגיבוי שלך באמצעות משפט סיסמה. + ייצא ידנית מפתחות + (מתקדם) + התחל להשתמש בגיבוי מקשים + הודעות בחדרים מוצפנים מאובטחות באמצעות הצפנה מקצה לקצה. רק אתה והנמען / ים יש את המקשים לקריאת ההודעות האלה. +\n +\nגבה את המפתחות שלך בצורה מאובטחת כדי לא לאבד אותם. + לעולם אל תאבד הודעות מוצפנות + אין מושב מטריקס זמין + אנא מחק את משפט הסיסמה אם ברצונך ש- Element ייצור מפתח שחזור. + משפט הסיסמה חלש מדי + אנא הזן משפט סיסמה + משפט הסיסמה אינו תואם + הזן ביטוי סיסמה + אשר את ביטוי הסיסמה + צור ביטוי סיסמה + לא נמצא APK חוקי של שירותי Google Play. ייתכן שההודעות לא יפעלו כראוי. + %d+ + +%d + %1$s: %2$s + %1$s: + רק עבור שגיאות + עבור הודעות ושגיאות + לעולם + הראה את אזור המידע + כווץ + הרחב + סליחה, שגיאה התרחשה + שרת הבית שלך עדיין לא תומך בטעינה עצלה של חברי החדר. נסה מאוחר יותר. + הגדל את הביצועים רק על ידי חברי חדר העמסה בתצוגה הראשונה. + טעינה עצלה של חברים וחדרים + אנא %s להמשיך להשתמש בשירות זה. + אנא %s כדי להגדיל מגבלה זו. + שרת בית זה הגיע למגבלת המשתמשים הפעילים החודשיים שלו. + שרת בית זה הגיע למגבלת המשתמשים הפעילים החודשיים כך ש חלק מהמשתמשים לא יוכלו להתחבר . + שרת בית זה חרג מאחד ממגבלות המשאבים שלו. + שרת בית זה חרג מאחד ממגבלות המשאבים שלו כך ש משתמשים מסוימים לא יוכלו להתחבר . + פנה למנהל השירות שלך + צור קשר עם מנהל המערכת + לחץ כאן כדי לראות הודעות ישנות יותר ממגבלת המשאבים + לחץ כאן לצפייה בהודעות ישנות יותר + החדר הזה הוא המשך לשיחה אחרת + השיחה נמשכת כאן + חדר זה הוחלף ואינו פעיל יותר + אנא הזינו את סיסמה שלכם. + אהא הזינו שם משתמש. + השבת חשבון + להמשך, הזן את הסיסמה שלך: + אנא שכח את כל ההודעות ששלחתי כאשר חשבוני מושבת (אזהרה: הדבר יגרום למשתמשים עתידיים לראות תצוגה חלקית של השיחות) + זה יהפוך את חשבונך ללא שימוש לצמיתות. לא תוכל להתחבר, ואף אחד לא יוכל לרשום מחדש את אותו מזהה משתמש. הדבר יביא לחשבונך לעזוב את כל החדרים בהם הוא משתתף, והוא יסיר את פרטי חשבונך משרת הזהות שלך. פעולה זו היא בלתי הפיכה . +\n +\nהשבתת חשבונך אינה גורמת לנו כברירת מחדל לשכוח הודעות ששלחת . אם תרצה שנשכח את ההודעות שלך, סמן את התיבה למטה. +\n +\nנראות ההודעות במטריקס דומה לדוא\"ל. המשמעות של שכחת ההודעות שלך היא שהודעות ששלחת לא ישותפו עם משתמשים חדשים או לא רשומים, אך למשתמשים רשומים שכבר יש גישה להודעות אלה עדיין תהיה גישה להעתק שלהם. + השבת חשבון + בדוק כעת + כדי להמשיך להשתמש בשרת הבית %1$s עליך לבדוק ולהסכים לתנאים ולהגבלות. + אווטאר + אוואטר התרעה + אווטאר קבלה + שכח חדר + לָשׁוּב וֵלְהִצְטַרֵף + סיבה: %1$s + חסום על ידי %2$s מ- %1$s + אתה נבעט מ- %1$s על ידי %2$s + מנהל הקהילה לא סיפק תיאור ארוך לקהילה זו. + + חדר %d + %d חדרים + %d חדרים + %d חדרים אחרים + + + חבר %d + %d חברים + %d חברים + %d חברים אחרים + + סנן קבוצות חדרים + סנן חברי קבוצה + הוזמנו + הצתרפו + חדרים + אין משתמשים + חדרים + אנשים + בית + דוגמא + מזהה קהילה + דוגמא + שם הקהילה + צור קהילה + צור + הודעה מוצפנת + רועש + שקט + כבוי + סימון ההפעלה הושבת. + סימון ההפעלה הופעל. + כדי לתקן את ניהול אפליקציות מטריקס + הפעלה / כיבוי של סימון MARKDOWN + משנה את כינוי התצוגה שלך + בועט משתמש עם מזהה נתון + הגדר את נושא החדר + עזוב חדר + מצטרף לחדר עם כינוי נתון + מזמין משתמש עם זיהוי נתון לחדר הנוכחי + משתמש מבוטל עם מזהה נתון + הגדר את רמת ההרשאה של המשתמש + הסר חסימה למשתמש עם מזהה נתון + חסום משתמש עם מזהה נתון + הצג פעולה + הפקודה \"%s\" זקוקה ליותר פרמטרים, או שחלק מהפרמטרים שגויים. + פקודה לא מוכרת: %s + שגיאת פקודה + שיחת ועידה נמצאת בפיתוח ואולי לא אמינה. + אזהרה! + התעלם + התעלם מהבקשה + בקשה לשיתוף מפתח + שיתוף + שתף ללא אימות + אמת + כפתור Enter על המקלדת הרכה ישלח הודעה במקום להוסיף מעבר שורה + שלח הודעה עם Enter + הצג תצוגה מקדימה של מדיה לפני השליחה + רטוט בעת אזכור משתמש + כולל שינויים באווטאר ושמות תצוגה. + הצג אירועי חשבון + הזמנות, בעיטות ואיסורים אינם מושפעים. + הראה אירועי הצטרפות ועזיבה + כולל אירועי הזמנה / הצטרפות / שמאל / בעיטה / איסור ושינוי שם אווטאר / תצוגה. + הצג אירועים של מדינת החברים בחדר + לחץ על אישורי הקריאה לרשימה מפורטת. + הצג קבלות הצג קבלות קריאה + הצג חותמות זמן בפורמט של 12 שעות + הצג חותמות זמן לכל ההודעות + עצב הודעות באמצעות תחביר הסימון לפני שהן נשלחות. זה מאפשר עיצוב מתקדם כגון שימוש בכוכביות להצגת טקסט נטוי. + עיצוב Markdown + הודע למשתמשים אחרים שאתה מקליד. + שלח הודעות הקלדה + תצוגה מקדימה של קישורים בצ\'אט כאשר שרת הבית שלך תומך בתכונה זו. + תצוגה מקדימה של כתובת אתר מוטמעת + מושבים + הצמד חדרים עם הודעות שלא נקראו + הצמד חדרים עם התראות שלא נענו + ארץ ספר הטלפונים + מסך ראשי + הרשאת אנשי קשר + אנשי קשר מקומיים + לעולם אל תאבד הודעות מוצפנות + להגן מפני אובדן גישה להודעות ונתונים מוצפנים + גיבוי מאובטח + התחל להשתמש בגיבוי מפתח + לעולם אל תאבד הודעות מוצפנות + זה היה אני + גיבוי מפתח חדש גיבוי חדש של מפתח הודעות מאובטח. +\n +\nאם לא הגדרת את שיטת השחזור החדשה, ייתכן שתוקף מנסה לגשת לחשבונך. שנה את סיסמת החשבון שלך והגדר מיד שיטת שחזור חדשה בהגדרות. + גיבוי מפתח חדש + מחק גיבוי למחוק את מפתחות ההצפנה המגובים שלך מהשרת\? לא תוכל עוד להשתמש במפתח השחזור שלך כדי לקרוא את היסטוריית ההודעות המוצפנת. + מחק את הגיבוי + בודק מצב גיבוי + מחיקת הגיבוי נכשלה (%s) + מוחק גיבוי … + כדי להשתמש בגיבוי מקשים בהפעלה זו, שחזר באמצעות משפט הסיסמה או מפתח השחזור שלך כעת. + נכשל קבלת פרטי אמון לגיבוי (%s). + לגיבוי יש חתימה לא חוקית מהפעלה %s לא מאומתת + לגיבוי יש חתימה לא חוקית מההפעלה %s המאומתת + לגיבוי יש חתימה חוקית מהפעלה %s לא מאומתת + לגיבוי יש חתימה מהפעלה לא ידועה עם מזהה %s. + לגיבוי יש חתימה חוקית מההפעלה המאומתת %s. + לגיבוי יש חתימה חוקית מהפגישה זו. + לא מגובים את המפתחות שלך מהפגישה זו. + גיבוי המפתח אינו פעיל בהפעלה זו. + גיבוי המפתח הוגדר כהלכה להפעלה זו. + מחק את הגיבוי + שחזר מגיבוי + הצפנת מושב אינה מופעלת + השגת הגרסה האחרונה של מפתחות השחזור (%s) נכשלה. + הגיבוי שוחזר %s! + לא ניתן היה לפענח את הגיבוי באמצעות מפתח שחזור זה: ודא שהזנת את מפתח השחזור הנכון. + אנא הכנס מפתח שחזור + בטל נעילת היסטוריה + מייבא מפתחות … + מוריד מקשים … + מפתח שחזור מחשוב … + שחזור הגיבוי: + שגיאת רשת: אנא בדוק את החיבור שלך ונסה שוב. + לא ניתן לפענח גיבוי באמצעות ביטוי סיסמה זה: אנא ודא שהזנת את ביטוי הסיסמה לשחזור הנכון. + איבדת את מפתח ההתאוששות שלך\? אתה יכול להגדיר אחד חדש בהגדרות. + שחזור הודעות + הזן מפתח שחזור + השתמש במפתח השחזור שלך כדי לפתוח את היסטוריית ההודעות המוצפנות שלך + אינך יודע את ביטוי הסיסמה לשחזור שלך, אתה יכול %s. + השתמש במפתח השחזור שלך + השתמש בביטוי הסיסמה לשחזור כדי לבטל את נעילת היסטוריית ההודעות המוצפנות שלך + מביא גרסת גיבוי … + אתה עלול לאבד גישה להודעות שלך אם אתה מתנתק או מאבד מכשיר זה. + האם אתה בטוח\? + מפתחות ההצפנה שלך מגובים כעת ברקע לשרת הבית שלך. הגיבוי הראשוני עשוי להימשך מספר דקות. + הגיבוי התחיל + שגיאה לא צפויה + מפתח שחזור + יצירת מפתח שחזור באמצעות ביטוי סיסמה, תהליך זה יכול להימשך מספר שניות. + שתף מפתח שחזור עם … + בבקשה צרו העתק + עצור + החלפה + נראה שכבר יש לך גיבוי מפתח הגדרה מהפעלה אחרת. האם אתה רוצה להחליף אותו לזה שאתה יוצר\? + גיבוי כבר קיים בשרת הבית שלך + מפתח השחזור נשמר. + מפתח השחזור נשמר ב- \'%s\'. +\n +\nאזהרה: קובץ זה עשוי להימחק אם הסרת ההתקנה של היישום. + שמירת קובץ בשם + שיתוף + שמור מפתח שחזור + הכנתי עותק + \ No newline at end of file From f0f0aafa1b7e13ceb71fd36110e7ac41246ce2ed Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 15 Jan 2021 11:13:36 +0100 Subject: [PATCH 224/224] Prepare release 1.0.14 --- CHANGES.md | 8 +------- fastlane/metadata/android/en-US/changelogs/40100130.txt | 2 +- fastlane/metadata/android/en-US/changelogs/40100140.txt | 2 ++ 3 files changed, 4 insertions(+), 8 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/40100140.txt diff --git a/CHANGES.md b/CHANGES.md index b666cf2712..135b881501 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,17 +24,11 @@ Bugfix 🐛: - Fix request too large Uri error when joining a room Translations 🗣: - - - -SDK API changes ⚠️: - - + - New language supported: Hebrew Build 🧱: - Remove dependency to org.greenrobot.eventbus library -Test: - - - Other changes: - Migrate to ViewBindings (#1072) diff --git a/fastlane/metadata/android/en-US/changelogs/40100130.txt b/fastlane/metadata/android/en-US/changelogs/40100130.txt index 39715c2910..dc517fac48 100644 --- a/fastlane/metadata/android/en-US/changelogs/40100130.txt +++ b/fastlane/metadata/android/en-US/changelogs/40100130.txt @@ -1,2 +1,2 @@ Main changes in this version: URL Preview, new Emoji keyboard, new room settings capabilities, and snow for Christmas! -Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.0.12 \ No newline at end of file +Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.0.13 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/40100140.txt b/fastlane/metadata/android/en-US/changelogs/40100140.txt new file mode 100644 index 0000000000..74f609fa15 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40100140.txt @@ -0,0 +1,2 @@ +Main changes in this version: Edit room permissions, automatic light/dark theme, and a bunch of bug fixes. +Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.0.14 \ No newline at end of file