Merge branch 'develop' into feature/fga/timeline_chunks_rework

This commit is contained in:
ganfra 2021-12-08 10:38:42 +01:00
commit bf1be4f20d
48 changed files with 183 additions and 171 deletions

View file

@ -38,12 +38,12 @@ allprojects {
repositories {
// For olm library. This has to be declared first, to ensure that Olm library is not downloaded from another repo
maven { url 'https://gitlab.matrix.org/api/v4/projects/27/packages/maven' }
maven {
url 'https://jitpack.io'
content {
// Use this repo only for olm library
includeGroupByRegex "org\\.matrix\\.gitlab\\.matrix-org"
// And also for FilePicker
// Use this repo only for FilePicker
includeGroupByRegex "com\\.github\\.jaiselrahman"
// And monarchy
includeGroupByRegex "com\\.github\\.Zhuinden"

1
changelog.d/4278.feature Normal file
View file

@ -0,0 +1 @@
Updates URL previews to match latest designs

1
changelog.d/4636.bugfix Normal file
View file

@ -0,0 +1 @@
Update log warning for call selection during voip calls.

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

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

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

@ -0,0 +1 @@
Upgrade OLM to v3.2.7 and get it from our maven repository.

View file

@ -11,7 +11,7 @@ def gradle = "7.0.3"
// Ref: https://kotlinlang.org/releases.html
def kotlin = "1.5.31"
def kotlinCoroutines = "1.5.2"
def dagger = "2.40.4"
def dagger = "2.40.5"
def retrofit = "2.9.0"
def arrow = "0.8.2"
def markwon = "4.6.2"

View file

@ -39,4 +39,7 @@
<!-- Navigation Drawer -->
<dimen name="navigation_drawer_max_width">320dp</dimen>
<!-- Preview Url -->
<dimen name="preview_url_view_corner_radius">8dp</dimen>
</resources>

View file

@ -140,8 +140,8 @@ dependencies {
implementation libs.arrow.core
implementation libs.arrow.instances
// olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm
implementation 'org.matrix.gitlab.matrix-org:olm:3.2.4'
// olm lib is now hosted by maven at https://gitlab.matrix.org/api/v4/projects/27/packages/maven
implementation 'org.matrix.android:olm:3.2.7'
// DI
implementation libs.dagger.dagger

View file

@ -205,8 +205,8 @@ internal class MxCallImpl(
Timber.tag(loggerTag.value).v("select answer $callId")
if (!isOutgoing) return
// This is an outgoing call, select the remote client that answered.
if (state != CallState.Dialing) {
Timber.tag(loggerTag.value).w("Expected state is CallState.Dialing got $state.")
if (state != CallState.Dialing && state !is CallState.Connected) {
Timber.tag(loggerTag.value).w("Expected state is CallState.Dialing or CallState.Connected got $state.")
}
CallSelectAnswerContent(
callId = callId,

View file

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

View file

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

View file

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

View file

@ -20,7 +20,7 @@ import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.view.isVisible
import androidx.core.view.isInvisible
import im.vector.app.R
import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration
import im.vector.app.features.themes.ThemeUtils
@ -38,28 +38,28 @@ class SendStateImageView @JvmOverloads constructor(
}
fun render(sendState: SendStateDecoration) {
isVisible = when (sendState) {
isInvisible = when (sendState) {
SendStateDecoration.SENDING_NON_MEDIA -> {
setImageResource(R.drawable.ic_sending_message)
imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary))
contentDescription = context.getString(R.string.event_status_a11y_sending)
true
false
}
SendStateDecoration.SENT -> {
setImageResource(R.drawable.ic_message_sent)
imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary))
contentDescription = context.getString(R.string.event_status_a11y_sent)
true
false
}
SendStateDecoration.FAILED -> {
setImageResource(R.drawable.ic_sending_message_failed)
imageTintList = null
contentDescription = context.getString(R.string.event_status_a11y_failed)
true
false
}
SendStateDecoration.SENDING_MEDIA,
SendStateDecoration.NONE -> {
false
true
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -43,22 +43,12 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
lateinit var dimensionConverter: DimensionConverter
protected var ignoreSendStatusVisibility = false
@CallSuper
override fun bind(holder: H) {
super.bind(holder)
holder.leftGuideline.updateLayoutParams<RelativeLayout.LayoutParams> {
this.marginStart = leftGuideline
}
// Ignore visibility of the send status icon?
holder.contentContainer.updateLayoutParams<RelativeLayout.LayoutParams> {
if (ignoreSendStatusVisibility) {
addRule(RelativeLayout.ALIGN_PARENT_END)
} else {
removeRule(RelativeLayout.ALIGN_PARENT_END)
}
}
holder.checkableBackground.isChecked = highlighted
}

View file

@ -33,10 +33,6 @@ import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlayb
@EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageVoiceItem : AbsMessageItem<MessageVoiceItem.Holder>() {
init {
ignoreSendStatusVisibility = true
}
@EpoxyAttribute
var mxcUrl: String = ""

View file

@ -19,13 +19,14 @@ package im.vector.app.features.home.room.detail.timeline.url
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import com.google.android.material.card.MaterialCardView
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.databinding.ViewUrlPreviewBinding
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.themes.ThemeUtils
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.media.PreviewUrlData
@ -36,7 +37,7 @@ class PreviewUrlView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener {
) : MaterialCardView(context, attrs, defStyleAttr), View.OnClickListener {
private lateinit var views: ViewUrlPreviewBinding
@ -44,6 +45,9 @@ class PreviewUrlView @JvmOverloads constructor(
init {
setupView()
radius = resources.getDimensionPixelSize(R.dimen.preview_url_view_corner_radius).toFloat()
cardElevation = 0f
setCardBackgroundColor(ThemeUtils.getColor(context, R.attr.vctr_system))
}
private var state: PreviewUrlUiState = PreviewUrlUiState.Unknown
@ -121,9 +125,15 @@ class PreviewUrlView @JvmOverloads constructor(
private fun renderData(previewUrlData: PreviewUrlData, imageContentRenderer: ImageContentRenderer) {
isVisible = true
views.urlPreviewTitle.setTextOrHide(previewUrlData.title)
views.urlPreviewImage.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, views.urlPreviewImage) }.orFalse()
views.urlPreviewDescription.setTextOrHide(previewUrlData.description)
views.urlPreviewDescription.maxLines = when {
previewUrlData.mxcUrl != null -> 2
previewUrlData.title != null -> 3
else -> 5
}
views.urlPreviewSite.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title })
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillAlpha="0.9"
android:fillColor="?vctr_content_quinary"
android:pathData="M24,12C24,18.6274 18.6274,24 12,24C5.3726,24 0,18.6274 0,12C0,5.3726 5.3726,0 12,0C18.6274,0 24,5.3726 24,12Z"
android:strokeAlpha="0.9" />
<path
android:fillColor="#00000000"
android:pathData="M7.9998,7.9998L15.9998,15.9998"
android:strokeWidth="1.33333"
android:strokeColor="?vctr_content_secondary"
android:strokeLineCap="round" />
<path
android:fillColor="#00000000"
android:pathData="M16.0005,7.9998L8.0006,15.9998"
android:strokeWidth="1.33333"
android:strokeColor="?vctr_content_secondary"
android:strokeLineCap="round" />
</vector>

View file

@ -80,6 +80,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/messageMemberNameView"
android:layout_marginEnd="8dp"
android:layout_toStartOf="@id/messageSendStateImageView"
android:layout_toEndOf="@id/messageStartGuideline"
android:addStatesFromChildren="true">
@ -115,27 +116,23 @@
android:id="@+id/messageContentRedactedStub"
style="@style/TimelineContentStubBaseParams"
android:layout_height="wrap_content"
android:layout_marginEnd="56dp"
android:layout="@layout/item_timeline_event_redacted_stub" />
<ViewStub
android:id="@+id/messagePollStub"
style="@style/TimelineContentStubBaseParams"
android:layout_height="wrap_content"
android:layout_marginEnd="56dp"
android:layout="@layout/item_timeline_event_poll_stub" />
<ViewStub
android:id="@+id/messageOptionsStub"
style="@style/TimelineContentStubBaseParams"
android:layout_height="wrap_content"
android:layout_marginEnd="56dp"
android:layout="@layout/item_timeline_event_option_buttons_stub" />
<ViewStub
android:id="@+id/messageContentVoiceStub"
style="@style/TimelineContentStubBaseParams"
android:layout_marginEnd="56dp"
android:layout="@layout/item_timeline_event_voice_stub"
tools:visibility="visible" />
@ -152,7 +149,7 @@
android:layout_marginBottom="4dp"
android:contentDescription="@string/event_status_a11y_sending"
android:src="@drawable/ic_sending_message"
android:visibility="gone"
android:visibility="invisible"
tools:tint="?vctr_content_tertiary"
tools:visibility="visible" />

View file

@ -16,7 +16,7 @@
<im.vector.app.features.home.room.detail.timeline.url.PreviewUrlView
android:id="@+id/messageUrlPreview"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp"

View file

@ -1,89 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/informationUrlPreviewContainer"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
tools:parentTag="com.google.android.material.card.MaterialCardView">
<View
android:id="@+id/url_preview_left_border"
android:layout_width="2dp"
android:layout_height="0dp"
android:background="?vctr_content_tertiary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/url_preview_title"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="0dp"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="7dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="?vctr_content_primary"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/url_preview_close"
app:layout_constraintStart_toStartOf="@id/url_preview_left_border"
app:layout_constraintTop_toTopOf="parent"
tools:text="Jo Malone denounces her former brand's John Boyega decision" />
android:orientation="vertical">
<ImageView
android:id="@+id/url_preview_image"
android:layout_width="0dp"
android:layout_height="157dp"
android:layout_marginTop="16dp"
android:importantForAccessibility="no"
android:scaleType="fitStart"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/url_preview_title"
app:layout_constraintTop_toBottomOf="@id/url_preview_title"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageView
android:id="@+id/url_preview_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:importantForAccessibility="no"
android:maxHeight="200dp"
android:scaleType="fitXY"
tools:src="@tools:sample/backgrounds/scenic" />
<TextView
android:id="@+id/url_preview_description"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="7dp"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:maxLines="4"
android:textColor="?vctr_content_secondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/url_preview_left_border"
app:layout_constraintTop_toBottomOf="@id/url_preview_image"
tools:text="The British perfumer says removing actor John Boyega from his own advert was “utterly despicable”." />
<TextView
android:id="@+id/url_preview_site"
style="@style/Widget.Vector.TextView.Caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="?vctr_content_secondary"
tools:text="BBC News" />
<TextView
android:id="@+id/url_preview_site"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="7dp"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="?vctr_content_tertiary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/url_preview_left_border"
app:layout_constraintTop_toBottomOf="@id/url_preview_description"
tools:text="BBC News" />
<TextView
android:id="@+id/url_preview_title"
style="@style/Widget.Vector.TextView.Body.Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="@dimen/layout_touch_size"
android:ellipsize="end"
android:maxLines="2"
android:textColor="?vctr_content_primary"
android:textStyle="bold"
tools:text="Jo Malone denounces her former brand's John Boyega decision" />
<TextView
android:id="@+id/url_preview_description"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ellipsize="end"
android:textColor="?vctr_content_secondary"
tools:text="The British perfumer says removing actor John Boyega from his own advert was “utterly despicable”." />
</LinearLayout>
<ImageView
android:id="@+id/url_preview_close"
android:layout_width="@dimen/layout_touch_size"
android:layout_height="@dimen/layout_touch_size"
android:layout_gravity="top|end"
android:contentDescription="@string/action_close"
android:scaleType="center"
android:src="@drawable/ic_close_24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?vctr_content_secondary"
android:src="@drawable/ic_close_with_circular_bg"
tools:ignore="MissingPrefix" />
</merge>