Simplify ForwardMessagesState by using AsyncAction.
This commit is contained in:
committed by
Benoit Marty
parent
e6fab7eee2
commit
130bce178a
@@ -36,7 +36,6 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectEntryPoint
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@ContributesNode(RoomScope::class)
|
||||
@@ -99,7 +98,7 @@ class ForwardMessagesNode @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun onForwardSuccess(roomIds: ImmutableList<RoomId>) {
|
||||
private fun onForwardSuccess(roomIds: List<RoomId>) {
|
||||
navigateUp()
|
||||
if (roomIds.size == 1) {
|
||||
val targetRoomId = roomIds.first()
|
||||
|
||||
@@ -18,15 +18,13 @@ package io.element.android.features.messages.impl.forward
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
||||
@@ -38,7 +36,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
class ForwardMessagesPresenter @AssistedInject constructor(
|
||||
@Assisted eventId: String,
|
||||
private val matrixCoroutineScope: CoroutineScope,
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
private val timelineProvider: TimelineProvider,
|
||||
) : Presenter<ForwardMessagesState> {
|
||||
private val eventId: EventId = EventId(eventId)
|
||||
@@ -48,28 +46,22 @@ class ForwardMessagesPresenter @AssistedInject constructor(
|
||||
fun create(eventId: String): ForwardMessagesPresenter
|
||||
}
|
||||
|
||||
private val forwardingActionState: MutableState<AsyncData<ImmutableList<RoomId>>> = mutableStateOf(AsyncData.Uninitialized)
|
||||
private val forwardingActionState: MutableState<AsyncAction<List<RoomId>>> = mutableStateOf(AsyncAction.Uninitialized)
|
||||
|
||||
fun onRoomSelected(roomIds: List<RoomId>) {
|
||||
matrixCoroutineScope.forwardEvent(eventId, roomIds.toPersistentList(), forwardingActionState)
|
||||
appCoroutineScope.forwardEvent(eventId, roomIds.toPersistentList(), forwardingActionState)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun present(): ForwardMessagesState {
|
||||
val forwardingSucceeded by remember {
|
||||
derivedStateOf { forwardingActionState.value.dataOrNull() }
|
||||
}
|
||||
|
||||
fun handleEvents(event: ForwardMessagesEvents) {
|
||||
when (event) {
|
||||
ForwardMessagesEvents.ClearError -> forwardingActionState.value = AsyncData.Uninitialized
|
||||
ForwardMessagesEvents.ClearError -> forwardingActionState.value = AsyncAction.Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
return ForwardMessagesState(
|
||||
isForwarding = forwardingActionState.value.isLoading(),
|
||||
error = (forwardingActionState.value as? AsyncData.Failure)?.error,
|
||||
forwardingSucceeded = forwardingSucceeded,
|
||||
forwardAction = forwardingActionState.value,
|
||||
eventSink = { handleEvents(it) }
|
||||
)
|
||||
}
|
||||
@@ -77,12 +69,11 @@ class ForwardMessagesPresenter @AssistedInject constructor(
|
||||
private fun CoroutineScope.forwardEvent(
|
||||
eventId: EventId,
|
||||
roomIds: ImmutableList<RoomId>,
|
||||
isForwardMessagesState: MutableState<AsyncData<ImmutableList<RoomId>>>,
|
||||
isForwardMessagesState: MutableState<AsyncAction<List<RoomId>>>,
|
||||
) = launch {
|
||||
isForwardMessagesState.value = AsyncData.Loading()
|
||||
timelineProvider.getActiveTimeline().forwardEvent(eventId, roomIds).fold(
|
||||
{ isForwardMessagesState.value = AsyncData.Success(roomIds) },
|
||||
{ isForwardMessagesState.value = AsyncData.Failure(it) }
|
||||
)
|
||||
suspend {
|
||||
timelineProvider.getActiveTimeline().forwardEvent(eventId, roomIds).getOrThrow()
|
||||
roomIds
|
||||
}.runCatchingUpdatingState(isForwardMessagesState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,10 @@
|
||||
|
||||
package io.element.android.features.messages.impl.forward
|
||||
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class ForwardMessagesState(
|
||||
// TODO Migrate to an Async
|
||||
val isForwarding: Boolean,
|
||||
val error: Throwable?,
|
||||
val forwardingSucceeded: ImmutableList<RoomId>?,
|
||||
val forwardAction: AsyncAction<List<RoomId>>,
|
||||
val eventSink: (ForwardMessagesEvents) -> Unit
|
||||
)
|
||||
|
||||
@@ -17,34 +17,30 @@
|
||||
package io.element.android.features.messages.impl.forward
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
open class ForwardMessagesStateProvider : PreviewParameterProvider<ForwardMessagesState> {
|
||||
override val values: Sequence<ForwardMessagesState>
|
||||
get() = sequenceOf(
|
||||
aForwardMessagesState(),
|
||||
aForwardMessagesState(
|
||||
isForwarding = true,
|
||||
forwardAction = AsyncAction.Loading,
|
||||
),
|
||||
aForwardMessagesState(
|
||||
forwardingSucceeded = persistentListOf(RoomId("!room2:domain")),
|
||||
forwardAction = AsyncAction.Success(
|
||||
listOf(RoomId("!room2:domain")),
|
||||
)
|
||||
),
|
||||
aForwardMessagesState(
|
||||
error = Throwable("error"),
|
||||
forwardAction = AsyncAction.Failure(Throwable("error")),
|
||||
),
|
||||
// Add other states here
|
||||
)
|
||||
}
|
||||
|
||||
fun aForwardMessagesState(
|
||||
isForwarding: Boolean = false,
|
||||
error: Throwable? = null,
|
||||
forwardingSucceeded: ImmutableList<RoomId>? = null,
|
||||
forwardAction: AsyncAction<List<RoomId>> = AsyncAction.Uninitialized,
|
||||
) = ForwardMessagesState(
|
||||
isForwarding = isForwarding,
|
||||
error = error,
|
||||
forwardingSucceeded = forwardingSucceeded,
|
||||
forwardAction = forwardAction,
|
||||
eventSink = {}
|
||||
)
|
||||
|
||||
@@ -17,45 +17,25 @@
|
||||
package io.element.android.features.messages.impl.forward
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialogDefaults
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
fun ForwardMessagesView(
|
||||
state: ForwardMessagesState,
|
||||
onForwardSuccess: (ImmutableList<RoomId>) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onForwardSuccess: (List<RoomId>) -> Unit,
|
||||
) {
|
||||
if (state.forwardingSucceeded != null) {
|
||||
onForwardSuccess(state.forwardingSucceeded)
|
||||
return
|
||||
}
|
||||
|
||||
if (state.isForwarding) {
|
||||
ProgressDialog(modifier)
|
||||
}
|
||||
|
||||
if (state.error != null) {
|
||||
ForwardingErrorDialog(
|
||||
modifier = modifier,
|
||||
onDismiss = { state.eventSink(ForwardMessagesEvents.ClearError) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ForwardingErrorDialog(onDismiss: () -> Unit, modifier: Modifier = Modifier) {
|
||||
ErrorDialog(
|
||||
content = ErrorDialogDefaults.title,
|
||||
onDismiss = onDismiss,
|
||||
modifier = modifier,
|
||||
AsyncActionView(
|
||||
async = state.forwardAction,
|
||||
onSuccess = {
|
||||
onForwardSuccess(it)
|
||||
},
|
||||
onErrorDismiss = {
|
||||
state.eventSink(ForwardMessagesEvents.ClearError)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
@@ -28,13 +29,11 @@ import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
class ForwardMessagesPresenterTest {
|
||||
@get:Rule
|
||||
@@ -47,9 +46,7 @@ class ForwardMessagesPresenterTest {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.isForwarding).isFalse()
|
||||
assertThat(initialState.error).isNull()
|
||||
assertThat(initialState.forwardingSucceeded).isNull()
|
||||
assertThat(initialState.forwardAction.isUninitialized()).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +67,10 @@ class ForwardMessagesPresenterTest {
|
||||
val summary = aRoomSummaryDetails()
|
||||
presenter.onRoomSelected(listOf(summary.roomId))
|
||||
val forwardingState = awaitItem()
|
||||
assertThat(forwardingState.isForwarding).isTrue()
|
||||
assertThat(forwardingState.forwardAction.isLoading()).isTrue()
|
||||
val successfulForwardState = awaitItem()
|
||||
assertThat(successfulForwardState.isForwarding).isFalse()
|
||||
assertThat(successfulForwardState.forwardingSucceeded).isNotNull()
|
||||
assert(forwardEventLambda).isCalledOnce()
|
||||
assertThat(successfulForwardState.forwardAction).isEqualTo(AsyncAction.Success(listOf(summary.roomId)))
|
||||
forwardEventLambda.assertions().isCalledOnce()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,11 +92,11 @@ class ForwardMessagesPresenterTest {
|
||||
presenter.onRoomSelected(listOf(summary.roomId))
|
||||
skipItems(1)
|
||||
val failedForwardState = awaitItem()
|
||||
assertThat(failedForwardState.error).isNotNull()
|
||||
assertThat(failedForwardState.forwardAction.isFailure()).isTrue()
|
||||
// Then clear error
|
||||
failedForwardState.eventSink(ForwardMessagesEvents.ClearError)
|
||||
assertThat(awaitItem().error).isNull()
|
||||
assert(forwardEventLambda).isCalledOnce()
|
||||
assertThat(awaitItem().forwardAction.isUninitialized()).isTrue()
|
||||
forwardEventLambda.assertions().isCalledOnce()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +107,6 @@ class ForwardMessagesPresenterTest {
|
||||
) = ForwardMessagesPresenter(
|
||||
eventId = eventId.value,
|
||||
timelineProvider = LiveTimelineProvider(fakeMatrixRoom),
|
||||
matrixCoroutineScope = coroutineScope,
|
||||
appCoroutineScope = coroutineScope,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user