Async API improvements "v2" (#672)
* Async API improvements "v2" **NB: This PR actually changes only 3 files in `libraries/architecture/`. All the other changes are automated refactors to fix the calling code.** This is a proposal for improvements to our `Async` type as discussed in: https://github.com/vector-im/element-x-android/pull/598/files#r1230664392 and in other chats. Please bear in mind it is just a proposal, I'd love to hear your feedback about it, especially when it comes to naming: I've tried to make parameter and function names use a terminology similar to what we find in the Kotlin stdlib and its `Result` type. I'm inclined to like more the non-extension flavours of the new `run*` APIs, though I'd also like your feedback about what API shape you prefer. ### Summary of the changes: #### Functional - Adds `exceptionOrNull()` API to complement the existing `dataOrNull()` API. - Adds `isFailure()`, `isLoading()`, `isSuccess()` and `isUninitialized()` courtesy APIs. - Renames `executeResult()` to `runUpdatingState()`: - Becomes the base API to which all the other similarly named APIs call into. - Makes it inline. - Adds contract. - Passes over any `prevData` to newre Async states. - Passes through the `block`s return value. - Adds unit tests. - Renames `execute` to `runCatchingUpdatingState()` and makes it just call into `runUpdatingState()` - Adds extension function overloads to the `run*` functions to accept `MutableState` as receiver #### Cosmetics - Reorders classes and methods in alphabetic order. - Reorder parameter names to mimic conventions in Kotlin stdlib. - Adds docstrings where useful. * Use `fold()` * rename pop to popFirst * Add docstrings * Please Detekt * Rename exception to error. * Please detekt * Update existing usages.
This commit is contained in:
parent
01ea66e60e
commit
316d57d1b6
25 changed files with 286 additions and 75 deletions
|
|
@ -27,7 +27,7 @@ import dagger.assisted.AssistedInject
|
|||
import io.element.android.features.messages.impl.attachments.Attachment
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.executeResult
|
||||
import io.element.android.libraries.architecture.runUpdatingState
|
||||
import io.element.android.libraries.mediaupload.api.MediaSender
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -83,8 +83,8 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
|
|||
mediaAttachment: Attachment.Media,
|
||||
sendActionState: MutableState<Async<Unit>>,
|
||||
) {
|
||||
suspend {
|
||||
sendActionState.runUpdatingState {
|
||||
mediaSender.sendMedia(mediaAttachment.localMedia.uri, mediaAttachment.localMedia.info.mimeType, mediaAttachment.compressIfPossible)
|
||||
}.executeResult(sendActionState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,12 @@ import androidx.compose.runtime.derivedStateOf
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.isLoading
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
|||
|
||||
private fun CoroutineScope.saveOnDisk(localMedia: Async<LocalMedia>) = launch {
|
||||
if (localMedia is Async.Success) {
|
||||
localMediaActions.saveOnDisk(localMedia.state)
|
||||
localMediaActions.saveOnDisk(localMedia.data)
|
||||
.onSuccess {
|
||||
val snackbarMessage = SnackbarMessage(StringR.string.common_file_saved_on_disk_android)
|
||||
snackbarDispatcher.post(snackbarMessage)
|
||||
|
|
@ -131,7 +131,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
|||
|
||||
private fun CoroutineScope.share(localMedia: Async<LocalMedia>) = launch {
|
||||
if (localMedia is Async.Success) {
|
||||
localMediaActions.share(localMedia.state)
|
||||
localMediaActions.share(localMedia.data)
|
||||
.onFailure {
|
||||
val snackbarMessage = SnackbarMessage(mediaActionsError(it))
|
||||
snackbarDispatcher.post(snackbarMessage)
|
||||
|
|
@ -141,7 +141,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
|||
|
||||
private fun CoroutineScope.open(localMedia: Async<LocalMedia>) = launch {
|
||||
if (localMedia is Async.Success) {
|
||||
localMediaActions.open(localMedia.state)
|
||||
localMediaActions.open(localMedia.data)
|
||||
.onFailure {
|
||||
val snackbarMessage = SnackbarMessage(mediaActionsError(it))
|
||||
snackbarDispatcher.post(snackbarMessage)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ import io.element.android.features.messages.impl.media.local.LocalMediaView
|
|||
import io.element.android.features.messages.impl.media.local.MediaInfo
|
||||
import io.element.android.features.messages.impl.media.local.rememberLocalMediaViewState
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.isLoading
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.executeResult
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.architecture.runUpdatingState
|
||||
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
|
||||
import io.element.android.libraries.designsystem.utils.SnackbarMessage
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
|
|
@ -87,12 +86,12 @@ class ReportMessagePresenter @AssistedInject constructor(
|
|||
blockUser: Boolean,
|
||||
result: MutableState<Async<Unit>>,
|
||||
) = launch {
|
||||
suspend {
|
||||
result.runUpdatingState {
|
||||
val userIdToBlock = userId.takeIf { blockUser }
|
||||
room.reportContent(eventId, reason, userIdToBlock)
|
||||
.onSuccess {
|
||||
snackbarDispatcher.post(SnackbarMessage(StringR.string.common_report_submitted))
|
||||
}
|
||||
}.executeResult(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue