diff --git a/CHANGES.md b/CHANGES.md index f39242ed629..befb9d3adfa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,6 +23,7 @@ Translations 🗣: - SDK API changes ⚠️: + - StateService now exposes suspendable function instead of using MatrixCallback. - RawCacheStrategy has been moved and renamed to CacheStrategy - FileService: remove useless FileService.DownloadMode diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle index 37f41d0a2a2..a99b5856ba5 100644 --- a/matrix-sdk-android-rx/build.gradle +++ b/matrix-sdk-android-rx/build.gradle @@ -38,6 +38,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version" // Paging implementation "androidx.paging:paging-runtime-ktx:2.1.2" diff --git a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt index bf4bcacc315..b938f60e39e 100644 --- a/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt +++ b/matrix-sdk-android-rx/src/main/java/org/matrix/android/sdk/rx/RxRoom.kt @@ -17,14 +17,20 @@ package org.matrix.android.sdk.rx import android.net.Uri +import io.reactivex.Completable +import io.reactivex.Observable +import io.reactivex.Single +import kotlinx.coroutines.rx2.rxCompletable import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary +import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.ReadReceipt import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility +import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState @@ -32,11 +38,6 @@ import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional -import io.reactivex.Completable -import io.reactivex.Observable -import io.reactivex.Single -import org.matrix.android.sdk.api.session.room.model.GuestAccess -import org.matrix.android.sdk.api.session.room.model.RoomJoinRules class RxRoom(private val room: Room) { @@ -121,28 +122,28 @@ class RxRoom(private val room: Room) { room.invite3pid(threePid, it) } - fun updateTopic(topic: String): Completable = completableBuilder { - room.updateTopic(topic, it) + fun updateTopic(topic: String): Completable = rxCompletable { + room.updateTopic(topic) } - fun updateName(name: String): Completable = completableBuilder { - room.updateName(name, it) + fun updateName(name: String): Completable = rxCompletable { + room.updateName(name) } - fun updateHistoryReadability(readability: RoomHistoryVisibility): Completable = completableBuilder { - room.updateHistoryReadability(readability, it) + fun updateHistoryReadability(readability: RoomHistoryVisibility): Completable = rxCompletable { + room.updateHistoryReadability(readability) } - fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?): Completable = completableBuilder { - room.updateJoinRule(joinRules, guestAccess, it) + fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?): Completable = rxCompletable { + room.updateJoinRule(joinRules, guestAccess) } - fun updateAvatar(avatarUri: Uri, fileName: String): Completable = completableBuilder { - room.updateAvatar(avatarUri, fileName, it) + fun updateAvatar(avatarUri: Uri, fileName: String): Completable = rxCompletable { + room.updateAvatar(avatarUri, fileName) } - fun deleteAvatar(): Completable = completableBuilder { - room.deleteAvatar(it) + fun deleteAvatar(): Completable = rxCompletable { + room.deleteAvatar() } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt index e42059c6397..da5e90abddb 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt @@ -17,13 +17,13 @@ package org.matrix.android.sdk.internal.crypto.encryption import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlinx.coroutines.runBlocking import org.amshove.kluent.shouldBe import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest -import org.matrix.android.sdk.api.NoOpMatrixCallback 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.Room @@ -57,13 +57,14 @@ class EncryptionTest : InstrumentedTest { @Test fun test_EncryptionStateEvent() { performTest(roomShouldBeEncrypted = true) { room -> - // Send an encryption Event as a State Event - room.sendStateEvent( - eventType = EventType.STATE_ROOM_ENCRYPTION, - stateKey = null, - body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent(), - callback = NoOpMatrixCallback() - ) + runBlocking { + // Send an encryption Event as a State Event + room.sendStateEvent( + eventType = EventType.STATE_ROOM_ENCRYPTION, + stateKey = null, + body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() + ) + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt index 74e3faf38a7..444366e9128 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt @@ -18,13 +18,11 @@ package org.matrix.android.sdk.api.session.room.state import android.net.Uri import androidx.lifecycle.LiveData -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRules -import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.Optional @@ -33,41 +31,41 @@ interface StateService { /** * Update the topic of the room */ - fun updateTopic(topic: String, callback: MatrixCallback): Cancelable + suspend fun updateTopic(topic: String) /** * Update the name of the room */ - fun updateName(name: String, callback: MatrixCallback): Cancelable + suspend fun updateName(name: String) /** * Update the canonical alias of the room * @param alias the canonical alias, or null to reset the canonical alias of this room * @param altAliases the alternative aliases for this room. It should include the canonical alias if any. */ - fun updateCanonicalAlias(alias: String?, altAliases: List, callback: MatrixCallback): Cancelable + suspend fun updateCanonicalAlias(alias: String?, altAliases: List) /** * Update the history readability of the room */ - fun updateHistoryReadability(readability: RoomHistoryVisibility, callback: MatrixCallback): Cancelable + suspend fun updateHistoryReadability(readability: RoomHistoryVisibility) /** * Update the join rule and/or the guest access */ - fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?, callback: MatrixCallback): Cancelable + suspend fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?) /** * Update the avatar of the room */ - fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback): Cancelable + suspend fun updateAvatar(avatarUri: Uri, fileName: String) /** * Delete the avatar of the room */ - fun deleteAvatar(callback: MatrixCallback): Cancelable + suspend fun deleteAvatar() - fun sendStateEvent(eventType: String, stateKey: String?, body: JsonDict, callback: MatrixCallback): Cancelable + suspend fun sendStateEvent(eventType: String, stateKey: String?, body: JsonDict) fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event? 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 a93ec8e797d..b5465844507 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 @@ -20,7 +20,6 @@ import android.net.Uri import androidx.lifecycle.LiveData import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -32,23 +31,15 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent import org.matrix.android.sdk.api.session.room.state.StateService -import org.matrix.android.sdk.api.util.Cancelable 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 -import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.task.configureWith -import org.matrix.android.sdk.internal.task.launchToCallback -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers -import org.matrix.android.sdk.internal.util.awaitCallback internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String, private val stateEventDataSource: StateEventDataSource, - private val taskExecutor: TaskExecutor, private val sendStateTask: SendStateTask, - private val coroutineDispatchers: MatrixCoroutineDispatchers, private val fileUploader: FileUploader, private val addRoomAliasTask: AddRoomAliasTask ) : StateService { @@ -74,45 +65,38 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private return stateEventDataSource.getStateEventsLive(roomId, eventTypes, stateKey) } - override fun sendStateEvent( + override suspend fun sendStateEvent( eventType: String, stateKey: String?, - body: JsonDict, - callback: MatrixCallback - ): Cancelable { + body: JsonDict + ) { val params = SendStateTask.Params( roomId = roomId, stateKey = stateKey, eventType = eventType, body = body ) - return sendStateTask - .configureWith(params) { - this.callback = callback - } - .executeBy(taskExecutor) + sendStateTask.execute(params) } - override fun updateTopic(topic: String, callback: MatrixCallback): Cancelable { - return sendStateEvent( + override suspend fun updateTopic(topic: String) { + sendStateEvent( eventType = EventType.STATE_ROOM_TOPIC, body = mapOf("topic" to topic), - callback = callback, stateKey = null ) } - override fun updateName(name: String, callback: MatrixCallback): Cancelable { - return sendStateEvent( + override suspend fun updateName(name: String) { + sendStateEvent( eventType = EventType.STATE_ROOM_NAME, body = mapOf("name" to name), - callback = callback, stateKey = null ) } - override fun updateCanonicalAlias(alias: String?, altAliases: List, callback: MatrixCallback): Cancelable { - return sendStateEvent( + override suspend fun updateCanonicalAlias(alias: String?, altAliases: List) { + sendStateEvent( eventType = EventType.STATE_ROOM_CANONICAL_ALIAS, body = RoomCanonicalAliasContent( canonicalAlias = alias, @@ -124,64 +108,48 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private // Sort for the cleanup .sorted() ).toContent(), - callback = callback, stateKey = null ) } - override fun updateHistoryReadability(readability: RoomHistoryVisibility, callback: MatrixCallback): Cancelable { - return sendStateEvent( + override suspend fun updateHistoryReadability(readability: RoomHistoryVisibility) { + sendStateEvent( eventType = EventType.STATE_ROOM_HISTORY_VISIBILITY, body = mapOf("history_visibility" to readability), - callback = callback, stateKey = null ) } - override fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?, callback: MatrixCallback): Cancelable { - return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) { - if (joinRules != null) { - awaitCallback { - sendStateEvent( - eventType = EventType.STATE_ROOM_JOIN_RULES, - body = RoomJoinRulesContent(joinRules).toContent(), - callback = it, - stateKey = null - ) - } - } - if (guestAccess != null) { - awaitCallback { - sendStateEvent( - eventType = EventType.STATE_ROOM_GUEST_ACCESS, - body = RoomGuestAccessContent(guestAccess).toContent(), - callback = it, - stateKey = null - ) - } - } + override suspend fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?) { + if (joinRules != null) { + sendStateEvent( + eventType = EventType.STATE_ROOM_JOIN_RULES, + body = RoomJoinRulesContent(joinRules).toContent(), + stateKey = null + ) + } + if (guestAccess != null) { + sendStateEvent( + eventType = EventType.STATE_ROOM_GUEST_ACCESS, + body = RoomGuestAccessContent(guestAccess).toContent(), + stateKey = null + ) } } - override fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback): Cancelable { - return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) { - val response = fileUploader.uploadFromUri(avatarUri, fileName, MimeTypes.Jpeg) - awaitCallback { - sendStateEvent( - eventType = EventType.STATE_ROOM_AVATAR, - body = mapOf("url" to response.contentUri), - callback = it, - stateKey = null - ) - } - } + override suspend fun updateAvatar(avatarUri: Uri, fileName: String) { + val response = fileUploader.uploadFromUri(avatarUri, fileName, MimeTypes.Jpeg) + sendStateEvent( + eventType = EventType.STATE_ROOM_AVATAR, + body = mapOf("url" to response.contentUri), + stateKey = null + ) } - override fun deleteAvatar(callback: MatrixCallback): Cancelable { - return sendStateEvent( + override suspend fun deleteAvatar() { + sendStateEvent( eventType = EventType.STATE_ROOM_AVATAR, body = emptyMap(), - callback = callback, stateKey = null ) } 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 14085a58a67..21858438b90 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 @@ -292,9 +292,7 @@ class RoomDetailViewModel @AssistedInject constructor( private fun handleSetNewAvatar(action: RoomDetailAction.SetAvatarAction) { viewModelScope.launch(Dispatchers.IO) { try { - awaitCallback { - room.updateAvatar(action.newAvatarUri, action.newAvatarFileName, it) - } + room.updateAvatar(action.newAvatarUri, action.newAvatarFileName) _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) } catch (failure: Throwable) { _viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure)) @@ -854,8 +852,8 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) { - launchSlashCommandFlow { - room.updateTopic(changeTopic.topic, it) + launchSlashCommandFlowSuspendable { + room.updateTopic(changeTopic.topic) } } @@ -876,9 +874,9 @@ class RoomDetailViewModel @AssistedInject constructor( ?.content ?.toModel() ?: return - launchSlashCommandFlow { + launchSlashCommandFlowSuspendable { currentPowerLevelsContent.setUserPowerLevel(setUserPowerLevel.userId, setUserPowerLevel.powerLevel) - room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent(), it) + room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent()) } } @@ -920,6 +918,19 @@ class RoomDetailViewModel @AssistedInject constructor( lambda.invoke(matrixCallback) } + private fun launchSlashCommandFlowSuspendable(block: suspend () -> Unit) { + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) + viewModelScope.launch { + val event = try { + block() + RoomDetailViewEvents.SlashCommandResultOk + } catch (failure: Exception) { + RoomDetailViewEvents.SlashCommandResultError(failure) + } + _viewEvents.post(event) + } + } + private fun handleSendReaction(action: RoomDetailAction.SendReaction) { room.sendReaction(action.targetEventId, action.reaction) } 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 78562ea3518..39b58843087 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 @@ -166,9 +166,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v viewModelScope.launch { _viewEvents.post(RoomMemberProfileViewEvents.Loading()) try { - awaitCallback { - room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent(), it) - } + room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent()) _viewEvents.post(RoomMemberProfileViewEvents.OnSetPowerLevelSuccess) } catch (failure: Throwable) { _viewEvents.post(RoomMemberProfileViewEvents.Failure(failure)) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt index 5873d9ce8a9..f470eeefc27 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt @@ -30,7 +30,6 @@ 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.MatrixCallback import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType @@ -301,21 +300,20 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo private fun updateCanonicalAlias(canonicalAlias: String?, alternativeAliases: List, closeForm: Boolean) { postLoading(true) - room.updateCanonicalAlias(canonicalAlias, alternativeAliases, object : MatrixCallback { - override fun onSuccess(data: Unit) { + viewModelScope.launch { + try { + room.updateCanonicalAlias(canonicalAlias, alternativeAliases) setState { copy( isLoading = false, publishManuallyState = if (closeForm) RoomAliasViewState.AddAliasState.Closed else publishManuallyState ) } - } - - override fun onFailure(failure: Throwable) { + } catch (failure: Throwable) { postLoading(false) _viewEvents.post(RoomAliasViewEvents.Failure(failure)) } - }) + } } private fun handleAddLocalAlias() = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt index 9e402c675b9..9f15e62b3be 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt @@ -30,7 +30,6 @@ import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.BiFunction import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.query.QueryStringValue @@ -197,8 +196,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState room.sendStateEvent( eventType = EventType.STATE_ROOM_THIRD_PARTY_INVITE, stateKey = action.stateKey, - body = emptyMap(), - callback = NoOpMatrixCallback() + body = emptyMap() ) } } diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetPostAPIHandler.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetPostAPIHandler.kt index a4d759250d3..3906ea687cb 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetPostAPIHandler.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetPostAPIHandler.kt @@ -21,6 +21,9 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.app.R import im.vector.app.core.resources.StringProvider +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes @@ -310,12 +313,13 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo val params = HashMap() params["status"] = status - room.sendStateEvent( - eventType = EventType.PLUMBING, - stateKey = null, - body = params, - callback = createWidgetAPICallback(widgetPostAPIMediator, eventData) - ) + launchWidgetAPIAction(widgetPostAPIMediator, eventData) { + room.sendStateEvent( + eventType = EventType.PLUMBING, + stateKey = null, + body = params + ) + } } /** @@ -333,12 +337,14 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo Timber.d(description) val content = eventData["content"] as JsonDict val stateKey = "_$userId" - room.sendStateEvent( - eventType = EventType.BOT_OPTIONS, - stateKey = stateKey, - body = content, - callback = createWidgetAPICallback(widgetPostAPIMediator, eventData) - ) + + launchWidgetAPIAction(widgetPostAPIMediator, eventData) { + room.sendStateEvent( + eventType = EventType.BOT_OPTIONS, + stateKey = stateKey, + body = content + ) + } } /** @@ -456,4 +462,19 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo private fun createWidgetAPICallback(widgetPostAPIMediator: WidgetPostAPIMediator, eventData: JsonDict): WidgetAPICallback { return WidgetAPICallback(widgetPostAPIMediator, eventData, stringProvider) } + + private fun launchWidgetAPIAction(widgetPostAPIMediator: WidgetPostAPIMediator, eventData: JsonDict, block: suspend () -> Unit): Job { + return GlobalScope.launch { + kotlin.runCatching { + block() + }.fold( + onSuccess = { + widgetPostAPIMediator.sendSuccess(eventData) + }, + onFailure = { + widgetPostAPIMediator.sendError(stringProvider.getString(R.string.widget_integration_failed_to_send_request), eventData) + } + ) + } + } }