From e108534a2a7a4bcd112fe561fe0b2523019837c5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 30 Apr 2021 15:34:15 +0200 Subject: [PATCH] Improve file too big error detection and rendering (#3245) --- CHANGES.md | 1 + .../sdk/api/session/events/model/Event.kt | 12 +++++++ .../tasks/SendVerificationMessageTask.kt | 3 +- .../database/RealmSessionStoreMigration.kt | 13 +++++-- .../internal/database/mapper/EventMapper.kt | 1 + .../internal/database/model/EventEntity.kt | 3 ++ .../internal/session/content/FileUploader.kt | 21 +++++++++++ .../session/content/UploadContentWorker.kt | 4 ++- .../session/room/relation/EventEditor.kt | 1 + .../session/room/send/LocalEchoRepository.kt | 4 ++- .../MultipleEventSendingDispatcherWorker.kt | 7 +++- .../session/room/send/SendEventWorker.kt | 15 ++++++-- .../android/sdk/internal/util/FailureExt.kt | 36 +++++++++++++++++++ .../vector/app/core/error/ErrorFormatter.kt | 3 ++ .../home/room/detail/RoomDetailViewEvents.kt | 1 + .../home/room/detail/RoomDetailViewModel.kt | 7 ++-- .../action/MessageActionsEpoxyController.kt | 9 ++++- vector/src/main/res/values/strings.xml | 1 + 18 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt diff --git a/CHANGES.md b/CHANGES.md index 553abdda8e..d3e17e6980 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Improvements 🙌: - Add ability to install APK from directly from Element (#2381) - Delete and react to stickers (#3250) - Compress video before sending (#442) + - Improve file too big error detection (#3245) Bugfix 🐛: - Message states cosmetic changes (#3007) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt index 89b873febb..6400dd6444 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt @@ -28,6 +28,8 @@ import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import org.matrix.android.sdk.internal.di.MoshiProvider import org.json.JSONObject +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.failure.MatrixError import timber.log.Timber typealias Content = JsonDict @@ -90,6 +92,16 @@ data class Event( @Transient var sendState: SendState = SendState.UNKNOWN + @Transient + var sendStateDetails: String? = null + + fun sendStateError(): MatrixError? { + return sendStateDetails?.let { + val matrixErrorAdapter = MoshiProvider.providesMoshi().adapter(MatrixError::class.java) + tryOrNull { matrixErrorAdapter.fromJson(it) } + } + } + /** * The `age` value transcoded in a timestamp based on the device clock when the SDK received * the event from the home server. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt index d8b9d3cd86..7fa48c3da1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt @@ -23,6 +23,7 @@ import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository import org.matrix.android.sdk.internal.task.Task +import org.matrix.android.sdk.internal.util.toMatrixErrorStr import javax.inject.Inject internal interface SendVerificationMessageTask : Task { @@ -55,7 +56,7 @@ internal class DefaultSendVerificationMessageTask @Inject constructor( localEchoRepository.updateSendState(localId, event.roomId, SendState.SENT) return response.eventId } catch (e: Throwable) { - localEchoRepository.updateSendState(localId, event.roomId, SendState.UNDELIVERED) + localEchoRepository.updateSendState(localId, event.roomId, SendState.UNDELIVERED, e.toMatrixErrorStr()) throw e } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index ac72592a1e..05213b40e5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -43,7 +43,7 @@ import javax.inject.Inject class RealmSessionStoreMigration @Inject constructor() : RealmMigration { companion object { - const val SESSION_STORE_SCHEMA_VERSION = 10L + const val SESSION_STORE_SCHEMA_VERSION = 11L } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -59,6 +59,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { if (oldVersion <= 7) migrateTo8(realm) if (oldVersion <= 8) migrateTo9(realm) if (oldVersion <= 9) migrateTo10(realm) + if (oldVersion <= 10) migrateTo11(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -163,7 +164,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { ?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema) } - fun migrateTo9(realm: DynamicRealm) { + private fun migrateTo9(realm: DynamicRealm) { Timber.d("Step 8 -> 9") realm.schema.get("RoomSummaryEntity") @@ -201,7 +202,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { } } - fun migrateTo10(realm: DynamicRealm) { + private fun migrateTo10(realm: DynamicRealm) { Timber.d("Step 9 -> 10") realm.schema.create("SpaceChildSummaryEntity") ?.addField(SpaceChildSummaryEntityFields.ORDER, String::class.java) @@ -240,4 +241,10 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { ?.addRealmListField(RoomSummaryEntityFields.PARENTS.`$`, realm.schema.get("SpaceParentSummaryEntity")!!) ?.addRealmListField(RoomSummaryEntityFields.CHILDREN.`$`, realm.schema.get("SpaceChildSummaryEntity")!!) } + + private fun migrateTo11(realm: DynamicRealm) { + Timber.d("Step 10 -> 11") + realm.schema.get("EventEntity") + ?.addField(EventEntityFields.SEND_STATE_DETAILS, String::class.java) + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt index a4a2fadd21..613b38e340 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt @@ -80,6 +80,7 @@ internal object EventMapper { ).also { it.ageLocalTs = eventEntity.ageLocalTs it.sendState = eventEntity.sendState + it.sendStateDetails = eventEntity.sendStateDetails eventEntity.decryptionResultJson?.let { json -> try { it.mxDecryptionResult = MoshiProvider.providesMoshi().adapter(OlmDecryptionResult::class.java).fromJson(json) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt index fe59f4fceb..fcb171c617 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt @@ -22,6 +22,7 @@ import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult import org.matrix.android.sdk.internal.di.MoshiProvider import io.realm.RealmObject import io.realm.annotations.Index +import org.matrix.android.sdk.api.failure.MatrixError internal open class EventEntity(@Index var eventId: String = "", @Index var roomId: String = "", @@ -32,6 +33,8 @@ internal open class EventEntity(@Index var eventId: String = "", @Index var stateKey: String? = null, var originServerTs: Long? = null, @Index var sender: String? = null, + // Can contain a serialized MatrixError + var sendStateDetails: String? = null, var age: Long? = 0, var unsignedData: String? = null, var redacts: String? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt index 8fa595db30..f3974487f7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt @@ -31,12 +31,16 @@ import okhttp3.RequestBody.Companion.toRequestBody import okio.BufferedSink import okio.source import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.api.session.content.ContentUrlResolver +import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.internal.di.Authenticated import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.ProgressRequestBody import org.matrix.android.sdk.internal.network.awaitResponse import org.matrix.android.sdk.internal.network.toFailure +import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService import java.io.File import java.io.FileNotFoundException import java.io.IOException @@ -46,6 +50,7 @@ import javax.inject.Inject internal class FileUploader @Inject constructor(@Authenticated private val okHttpClient: OkHttpClient, private val globalErrorReceiver: GlobalErrorReceiver, + private val homeServerCapabilitiesService: DefaultHomeServerCapabilitiesService, private val context: Context, contentUrlResolver: ContentUrlResolver, moshi: Moshi) { @@ -57,6 +62,22 @@ internal class FileUploader @Inject constructor(@Authenticated filename: String?, mimeType: String?, progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { + // Check size limit + // DO NOT COMMIT: 5 Mo + val maxUploadFileSize = 5 * 1024 * 1024L // homeServerCapabilitiesService.getHomeServerCapabilities().maxUploadFileSize + + if (maxUploadFileSize != HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN + && file.length() > maxUploadFileSize) { + // Known limitation and file too big for the server, save the pain to upload it + throw Failure.ServerError( + error = MatrixError( + code = MatrixError.M_TOO_LARGE, + message = "Cannot upload files larger than ${maxUploadFileSize / 1048576L}mb" + ), + httpCode = 413 + ) + } + val uploadBody = object : RequestBody() { override fun contentLength() = file.length() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt index 660a0376e3..bc7d846e55 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt @@ -41,6 +41,7 @@ import org.matrix.android.sdk.internal.session.room.send.CancelSendTracker import org.matrix.android.sdk.internal.session.room.send.LocalEchoIdentifiers import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker +import org.matrix.android.sdk.internal.util.toMatrixErrorStr import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker import org.matrix.android.sdk.internal.worker.SessionWorkerParams import org.matrix.android.sdk.internal.worker.WorkerParamsFactory @@ -129,6 +130,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter } } + // TODO Send the Thumbnail after the main content, because the main content can fail if too large. val uploadThumbnailResult = dealWithThumbnail(params) val progressListener = object : ProgressRequestBody.Listener { @@ -304,7 +306,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter return Result.success( WorkerParamsFactory.toData( params.copy( - lastFailureMessage = failure.localizedMessage + lastFailureMessage = failure.toMatrixErrorStr() ) ) ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt index 5fe06287d2..a666d40fc3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt @@ -99,6 +99,7 @@ internal class EventEditor @Inject constructor(private val eventSenderProcessor: entity.age = editedEventEntity.age entity.originServerTs = editedEventEntity.originServerTs entity.sendState = editedEventEntity.sendState + entity.sendStateDetails = editedEventEntity.sendStateDetails } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt index 70245cbd5e..e98e5646af 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt @@ -87,7 +87,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private } } - fun updateSendState(eventId: String, roomId: String?, sendState: SendState) { + fun updateSendState(eventId: String, roomId: String?, sendState: SendState, sendStateDetails: String? = null) { Timber.v("## SendEvent: [${System.currentTimeMillis()}] Update local state of $eventId to ${sendState.name}") timelineInput.onLocalEchoUpdated(roomId = roomId ?: "", eventId = eventId, sendState = sendState) updateEchoAsync(eventId) { realm, sendingEventEntity -> @@ -96,6 +96,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private } else { sendingEventEntity.sendState = sendState } + sendingEventEntity.sendStateDetails = sendStateDetails roomSummaryUpdater.updateSendingInformation(realm, sendingEventEntity.roomId) } } @@ -161,6 +162,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private val timelineEvents = TimelineEventEntity.where(realm, roomId, eventIds).findAll() timelineEvents.forEach { it.root?.sendState = sendState + it.root?.sendStateDetails = null } roomSummaryUpdater.updateSendingInformation(realm, roomId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt index bc307bc74f..e889f1a61b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt @@ -55,7 +55,12 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo override fun doOnError(params: Params): Result { params.localEchoIds.forEach { localEchoIds -> - localEchoRepository.updateSendState(localEchoIds.eventId, localEchoIds.roomId, SendState.UNDELIVERED) + localEchoRepository.updateSendState( + eventId = localEchoIds.eventId, + roomId = localEchoIds.roomId, + sendState = SendState.UNDELIVERED, + sendStateDetails = params.lastFailureMessage + ) } return super.doOnError(params) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt index d55dce57af..cd7911910d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt @@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.internal.crypto.tasks.SendEventTask import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.SessionComponent +import org.matrix.android.sdk.internal.util.toMatrixErrorStr import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker import org.matrix.android.sdk.internal.worker.SessionWorkerParams import timber.log.Timber @@ -77,7 +78,12 @@ internal class SendEventWorker(context: Context, } if (params.lastFailureMessage != null) { - localEchoRepository.updateSendState(event.eventId, event.roomId, SendState.UNDELIVERED) + localEchoRepository.updateSendState( + eventId = event.eventId, + roomId = event.roomId, + sendState = SendState.UNDELIVERED, + sendStateDetails = params.lastFailureMessage + ) // Transmit the error return Result.success(inputData) .also { Timber.e("Work cancelled due to input error from parent") } @@ -90,7 +96,12 @@ internal class SendEventWorker(context: Context, } catch (exception: Throwable) { if (/*currentAttemptCount >= MAX_NUMBER_OF_RETRY_BEFORE_FAILING ||**/ !exception.shouldBeRetried()) { Timber.e("## SendEvent: [${System.currentTimeMillis()}] Send event Failed cannot retry ${params.eventId} > ${exception.localizedMessage}") - localEchoRepository.updateSendState(event.eventId, event.roomId, SendState.UNDELIVERED) + localEchoRepository.updateSendState( + eventId = event.eventId, + roomId = event.roomId, + sendState = SendState.UNDELIVERED, + sendStateDetails = exception.toMatrixErrorStr() + ) Result.success() } else { Timber.e("## SendEvent: [${System.currentTimeMillis()}] Send event Failed schedule retry ${params.eventId} > ${exception.localizedMessage}") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt new file mode 100644 index 0000000000..8c78feeac3 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt @@ -0,0 +1,36 @@ +/* + * 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. + * 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.util + +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.failure.MatrixError +import org.matrix.android.sdk.internal.di.MoshiProvider + +/** + * Try to extract and serialize a MatrixError, or default to localizedMessage + */ +internal fun Throwable.toMatrixErrorStr(): String { + return (this as? Failure.ServerError) + ?.let { + // Serialize the MatrixError in this case + val adapter = MoshiProvider.providesMoshi().adapter(MatrixError::class.java) + tryOrNull { adapter.toJson(error) } + } + ?: localizedMessage + ?: "error" +} diff --git a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt index d7f003574c..0a724b62c6 100644 --- a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt @@ -78,6 +78,9 @@ class DefaultErrorFormatter @Inject constructor( throwable.error.code == MatrixError.M_LIMIT_EXCEEDED -> { limitExceededError(throwable.error) } + throwable.error.code == MatrixError.M_TOO_LARGE -> { + stringProvider.getString(R.string.error_file_too_big_simple) + } throwable.error.code == MatrixError.M_THREEPID_NOT_FOUND -> { stringProvider.getString(R.string.login_reset_password_error_not_found) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt index b326700d5e..0a9ffd83ab 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt @@ -54,6 +54,7 @@ sealed class RoomDetailViewEvents : VectorViewEvents { object ShowWaitingView : RoomDetailViewEvents() object HideWaitingView : RoomDetailViewEvents() + // TODO Remove data class FileTooBigError( val filename: String, val fileSizeInBytes: Long, 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 1dd13bf481..e5e9b2c7d3 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 @@ -79,7 +79,6 @@ import org.matrix.android.sdk.api.session.events.model.isTextMessage 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.file.FileService -import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership @@ -292,7 +291,6 @@ class RoomDetailViewModel @AssistedInject constructor( is RoomDetailAction.HandleTombstoneEvent -> handleTombstoneEvent(action) is RoomDetailAction.ResendMessage -> handleResendEvent(action) is RoomDetailAction.RemoveFailedEcho -> handleRemove(action) - is RoomDetailAction.ResendAll -> handleResendAll() is RoomDetailAction.MarkAllAsRead -> handleMarkAllAsRead() is RoomDetailAction.ReportContent -> handleReportContent(action) is RoomDetailAction.IgnoreUser -> handleIgnoreUser(action) @@ -1107,6 +1105,10 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun handleSendMedia(action: RoomDetailAction.SendMedia) { + room.sendMedias(action.attachments, action.compressBeforeSending, emptySet()) + + /* + TODO Cleanup this error is now managed by the SDK val attachments = action.attachments val homeServerCapabilities = session.getHomeServerCapabilities() val maxUploadFileSize = homeServerCapabilities.maxUploadFileSize @@ -1124,6 +1126,7 @@ class RoomDetailViewModel @AssistedInject constructor( )) } } + */ } private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt index 30587e6659..d62083de30 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt @@ -28,6 +28,7 @@ import im.vector.app.core.epoxy.bottomsheet.bottomSheetMessagePreviewItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetQuickReactionsItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetSendStateItem import im.vector.app.core.epoxy.dividerItem +import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.home.AvatarRenderer @@ -38,6 +39,7 @@ import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovement import im.vector.app.features.home.room.detail.timeline.tools.linkify import im.vector.app.features.media.ImageContentRenderer import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.send.SendState import javax.inject.Inject @@ -50,6 +52,7 @@ class MessageActionsEpoxyController @Inject constructor( private val fontProvider: EmojiCompatFontProvider, private val imageContentRenderer: ImageContentRenderer, private val dimensionConverter: DimensionConverter, + private val errorFormatter: ErrorFormatter, private val dateFormatter: VectorDateFormatter ) : TypedEpoxyController() { @@ -74,10 +77,14 @@ class MessageActionsEpoxyController @Inject constructor( // Send state val sendState = state.sendState() if (sendState?.hasFailed().orFalse()) { + // Get more details about the error + val errorMessage = state.timelineEvent()?.root?.sendStateError() + ?.let { errorFormatter.toHumanReadable(Failure.ServerError(it, 0)) } + ?: stringProvider.getString(R.string.unable_to_send_message) bottomSheetSendStateItem { id("send_state") showProgress(false) - text(stringProvider.getString(R.string.unable_to_send_message)) + text(errorMessage) drawableStart(R.drawable.ic_warning_badge) } } else if (sendState?.isSending().orFalse()) { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 5dc21601a9..eadc0db1f4 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2295,6 +2295,7 @@ %d users read + "The file is too large to upload." "The file '%1$s' (%2$s) is too large to upload. The limit is %3$s." "An error occurred while retrieving the attachment."