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