diff --git a/CHANGES.md b/CHANGES.md index 4802f1bb12..13385123e6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Improvements 🙌: - Improve timeline filtering (dissociate membership and profile events, display hidden events when highlighted, fix hidden item/read receipts behavior) - Add better support for empty room name fallback (#3106) - Room list improvements (paging) + - Fix quick click action (#3127) Bugfix 🐛: - Fix bad theme change for the MainActivity @@ -23,6 +24,7 @@ Bugfix 🐛: - Disable URL preview for some domains (#2995) - Fix avatar rendering for DMs, after initial sync (#2693) - Fix mandatory parameter in API (#3065) + - If signout request fails, do not start LoginActivity, but restart the app (#3099) Translations 🗣: - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt index a2b4e135d1..c96a800ee5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageType.kt @@ -35,5 +35,5 @@ object MessageType { const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker" const val MSGTYPE_CONFETTI = "nic.custom.confetti" - const val MSGTYPE_SNOW = "nic.custom.snow" + const val MSGTYPE_SNOW = "io.element.effect.snowfall" } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt index d9f102c7e0..e39bce6c67 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt @@ -55,9 +55,13 @@ internal suspend inline fun executeRequest(globalErrorReceiver: GlobalErr else -> throwable } - // Log some details about the request which has failed. This is less useful than before... - // Timber.e("Exception when executing request ${apiCall.request().method} ${apiCall.request().url.toString().substringBefore("?")}") - Timber.e("Exception when executing request") + // Log some details about the request which has failed. + val request = (throwable as? HttpException)?.response()?.raw()?.request + if (request == null) { + Timber.e("Exception when executing request") + } else { + Timber.e("Exception when executing request ${request.method} ${request.url.toString().substringBefore("?")}") + } // Check if this is a certificateException CertUtil.getCertificateException(exception) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index 1ed142ce23..e230599f8f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -386,14 +386,14 @@ internal class DefaultTimeline( private fun getState(direction: Timeline.Direction): TimelineState { return when (direction) { - Timeline.Direction.FORWARDS -> forwardsState.get() + Timeline.Direction.FORWARDS -> forwardsState.get() Timeline.Direction.BACKWARDS -> backwardsState.get() } } private fun updateState(direction: Timeline.Direction, update: (TimelineState) -> TimelineState) { val stateReference = when (direction) { - Timeline.Direction.FORWARDS -> forwardsState + Timeline.Direction.FORWARDS -> forwardsState Timeline.Direction.BACKWARDS -> backwardsState } val currentValue = stateReference.get() @@ -604,12 +604,14 @@ internal class DefaultTimeline( return offsetResults.size } - private fun buildTimelineEvent(eventEntity: TimelineEventEntity) = timelineEventMapper.map( - timelineEventEntity = eventEntity, - buildReadReceipts = settings.buildReadReceipts - ).let { - // eventually enhance with ui echo? - (uiEchoManager.decorateEventWithReactionUiEcho(it) ?: it) + private fun buildTimelineEvent(eventEntity: TimelineEventEntity): TimelineEvent { + return timelineEventMapper.map( + timelineEventEntity = eventEntity, + buildReadReceipts = settings.buildReadReceipts + ).let { timelineEvent -> + // eventually enhance with ui echo? + uiEchoManager.decorateEventWithReactionUiEcho(timelineEvent) ?: timelineEvent + } } /** @@ -702,10 +704,10 @@ internal class DefaultTimeline( return object : MatrixCallback { override fun onSuccess(data: TokenChunkEventPersistor.Result) { when (data) { - TokenChunkEventPersistor.Result.SUCCESS -> { + TokenChunkEventPersistor.Result.SUCCESS -> { Timber.v("Success fetching $limit items $direction from pagination request") } - TokenChunkEventPersistor.Result.REACHED_END -> { + TokenChunkEventPersistor.Result.REACHED_END -> { postSnapshot() } TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE -> diff --git a/vector/src/main/java/im/vector/app/core/utils/FirstThrottler.kt b/vector/src/main/java/im/vector/app/core/utils/FirstThrottler.kt index 915e955fa6..3d52ca99db 100644 --- a/vector/src/main/java/im/vector/app/core/utils/FirstThrottler.kt +++ b/vector/src/main/java/im/vector/app/core/utils/FirstThrottler.kt @@ -15,6 +15,8 @@ */ package im.vector.app.core.utils +import android.os.SystemClock + /** * Simple ThrottleFirst * See https://raw.githubusercontent.com/wiki/ReactiveX/RxJava/images/rx-operators/throttleFirst.png @@ -23,7 +25,7 @@ class FirstThrottler(private val minimumInterval: Long = 800) { private var lastDate = 0L fun canHandle(): Boolean { - val now = System.currentTimeMillis() + val now = SystemClock.elapsedRealtime() if (now > lastDate + minimumInterval) { lastDate = now return true 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 e6c5abe20c..34e73c8702 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -161,25 +161,22 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity lifecycleScope.launch { try { session.signOut(!args.isUserLoggedOut) - Timber.w("SIGN_OUT: success, start app") - sessionHolder.clearActiveSession() - doLocalCleanup(clearPreferences = true) - startNextActivityAndFinish() } catch (failure: Throwable) { displayError(failure) + return@launch } + Timber.w("SIGN_OUT: success, start app") + sessionHolder.clearActiveSession() + doLocalCleanup(clearPreferences = true) + startNextActivityAndFinish() } } args.clearCache -> { lifecycleScope.launch { - try { - session.clearCache() - doLocalCleanup(clearPreferences = false) - session.startSyncing(applicationContext) - startNextActivityAndFinish() - } catch (failure: Throwable) { - displayError(failure) - } + session.clearCache() + doLocalCleanup(clearPreferences = false) + session.startSyncing(applicationContext) + startNextActivityAndFinish() } } } @@ -215,15 +212,16 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity .setTitle(R.string.dialog_title_error) .setMessage(errorFormatter.toHumanReadable(failure)) .setPositiveButton(R.string.global_retry) { _, _ -> doCleanUp() } - .setNegativeButton(R.string.cancel) { _, _ -> startNextActivityAndFinish() } + .setNegativeButton(R.string.cancel) { _, _ -> startNextActivityAndFinish(ignoreClearCredentials = true) } .setCancelable(false) .show() } } - private fun startNextActivityAndFinish() { + private fun startNextActivityAndFinish(ignoreClearCredentials: Boolean = false) { val intent = when { args.clearCredentials + && !ignoreClearCredentials && (!args.isUserLoggedOut || args.isAccountDeactivated) -> // User has explicitly asked to log out or deactivated his account LoginActivity.newIntent(this, null) 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 b2e7004d0f..b7e2e189d3 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 @@ -1675,10 +1675,12 @@ class RoomDetailFragment @Inject constructor( shareText(requireContext(), action.messageContent.body) } else if (action.messageContent is MessageWithAttachmentContent) { lifecycleScope.launch { - val data = session.fileService().downloadFile(messageContent = action.messageContent) - if (isAdded) { - shareMedia(requireContext(), data, getMimeTypeFromUri(requireContext(), data.toUri())) - } + val result = runCatching { session.fileService().downloadFile(messageContent = action.messageContent) } + if (!isAdded) return@launch + result.fold( + { shareMedia(requireContext(), it, getMimeTypeFromUri(requireContext(), it.toUri())) }, + { showErrorInSnackbar(it) } + ) } } } @@ -1701,16 +1703,22 @@ class RoomDetailFragment @Inject constructor( return } lifecycleScope.launch { - val data = session.fileService().downloadFile(messageContent = action.messageContent) - if (isAdded) { - saveMedia( - context = requireContext(), - file = data, - title = action.messageContent.body, - mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), data.toUri()), - notificationUtils = notificationUtils - ) - } + val result = runCatching { session.fileService().downloadFile(messageContent = action.messageContent) } + if (!isAdded) return@launch + result.fold( + { + saveMedia( + context = requireContext(), + file = it, + title = action.messageContent.body, + mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()), + notificationUtils = notificationUtils + ) + }, + { + showErrorInSnackbar(it) + } + ) } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt index bae4847f7e..1d6b056816 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt @@ -127,25 +127,27 @@ class RoomUploadsViewModel @AssistedInject constructor( private fun handleShare(action: RoomUploadsAction.Share) { viewModelScope.launch { - try { + val event = try { val file = session.fileService().downloadFile( messageContent = action.uploadEvent.contentWithAttachmentContent) - _viewEvents.post(RoomUploadsViewEvents.FileReadyForSharing(file)) + RoomUploadsViewEvents.FileReadyForSharing(file) } catch (failure: Throwable) { - _viewEvents.post(RoomUploadsViewEvents.Failure(failure)) + RoomUploadsViewEvents.Failure(failure) } + _viewEvents.post(event) } } private fun handleDownload(action: RoomUploadsAction.Download) { viewModelScope.launch { - try { + val event = try { val file = session.fileService().downloadFile( messageContent = action.uploadEvent.contentWithAttachmentContent) - _viewEvents.post(RoomUploadsViewEvents.FileReadyForSaving(file, action.uploadEvent.contentWithAttachmentContent.body)) + RoomUploadsViewEvents.FileReadyForSaving(file, action.uploadEvent.contentWithAttachmentContent.body) } catch (failure: Throwable) { - _viewEvents.post(RoomUploadsViewEvents.Failure(failure)) + RoomUploadsViewEvents.Failure(failure) } + _viewEvents.post(event) } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt index c9160b8ebc..17c5cad1c2 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt @@ -20,6 +20,7 @@ import androidx.preference.Preference import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.preference.VectorPreference +import im.vector.app.core.utils.FirstThrottler import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.displayInWebView import im.vector.app.core.utils.openAppSettingsPage @@ -36,6 +37,8 @@ class VectorSettingsHelpAboutFragment @Inject constructor( override var titleRes = R.string.preference_root_help_about override val preferenceXmlRes = R.xml.vector_settings_help_about + private val firstThrottler = FirstThrottler(1000) + override fun bindPref() { // preference to start the App info screen, to facilitate App permissions access findPreference(APP_INFO_LINK_PREFERENCE_KEY)!! @@ -98,7 +101,9 @@ class VectorSettingsHelpAboutFragment @Inject constructor( // third party notice findPreference(VectorPreferences.SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY)!! .onPreferenceClickListener = Preference.OnPreferenceClickListener { - activity?.displayInWebView(VectorSettingsUrls.THIRD_PARTY_LICENSES) + if (firstThrottler.canHandle()) { + activity?.displayInWebView(VectorSettingsUrls.THIRD_PARTY_LICENSES) + } false }