Skip to content

Commit

Permalink
Merge pull request #2166 from element-hq/feature/bma/fixFlakyTest
Browse files Browse the repository at this point in the history
Introduce AsyncAction with a Confirmation state and use it for logout action
  • Loading branch information
bmarty authored Jan 5, 2024
2 parents f5a229d + 1fcb8fe commit 4948748
Show file tree
Hide file tree
Showing 173 changed files with 1,154 additions and 1,022 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import io.element.android.features.call.data.WidgetMessage
import io.element.android.features.call.utils.CallWidgetProvider
import io.element.android.features.call.utils.WidgetMessageInterceptor
import io.element.android.features.call.utils.WidgetMessageSerializer
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
Expand Down Expand Up @@ -75,7 +75,7 @@ class CallScreenPresenter @AssistedInject constructor(
@Composable
override fun present(): CallScreenState {
val coroutineScope = rememberCoroutineScope()
val urlState = remember { mutableStateOf<Async<String>>(Async.Uninitialized) }
val urlState = remember { mutableStateOf<AsyncData<String>>(AsyncData.Uninitialized) }
val callWidgetDriver = remember { mutableStateOf<MatrixWidgetDriver?>(null) }
val messageInterceptor = remember { mutableStateOf<WidgetMessageInterceptor?>(null) }
var isJoinedCall by rememberSaveable { mutableStateOf(false) }
Expand Down Expand Up @@ -154,7 +154,7 @@ class CallScreenPresenter @AssistedInject constructor(

private fun CoroutineScope.loadUrl(
inputs: CallType,
urlState: MutableState<Async<String>>,
urlState: MutableState<AsyncData<String>>,
callWidgetDriver: MutableState<MatrixWidgetDriver?>,
) = launch {
urlState.runCatchingUpdatingState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

package io.element.android.features.call.ui

import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncData

data class CallScreenState(
val urlState: Async<String>,
val urlState: AsyncData<String>,
val userAgent: String,
val isInWidgetMode: Boolean,
val eventSink: (CallScreenEvents) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import androidx.compose.ui.viewinterop.AndroidView
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.call.R
import io.element.android.features.call.utils.WebViewWidgetMessageInterceptor
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
Expand Down Expand Up @@ -96,7 +96,7 @@ internal fun CallScreenView(

@Composable
private fun CallWebView(
url: Async<String>,
url: AsyncData<String>,
userAgent: String,
onPermissionsRequested: (PermissionRequest) -> Unit,
onWebViewCreated: (WebView) -> Unit,
Expand All @@ -116,7 +116,7 @@ private fun CallWebView(
}
},
update = { webView ->
if (url is Async.Success && webView.url != url.data) {
if (url is AsyncData.Success && webView.url != url.data) {
webView.loadUrl(url.data)
}
},
Expand Down Expand Up @@ -161,7 +161,7 @@ internal fun CallScreenViewPreview() {
ElementPreview {
CallScreenView(
state = CallScreenState(
urlState = Async.Success("https://call.element.io/some-actual-call?with=parameters"),
urlState = AsyncData.Success("https://call.element.io/some-actual-call?with=parameters"),
isInWidgetMode = false,
userAgent = "",
eventSink = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.call.CallType
import io.element.android.features.call.utils.FakeCallWidgetProvider
import io.element.android.features.call.utils.FakeWidgetMessageInterceptor
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.test.A_ROOM_ID
Expand Down Expand Up @@ -62,7 +62,7 @@ class CallScreenPresenterTest {
skipItems(1)

val initialState = awaitItem()
assertThat(initialState.urlState).isEqualTo(Async.Success("https://call.element.io"))
assertThat(initialState.urlState).isEqualTo(AsyncData.Success("https://call.element.io"))
assertThat(initialState.isInWidgetMode).isFalse()
}
}
Expand All @@ -83,7 +83,7 @@ class CallScreenPresenterTest {
skipItems(1)

val initialState = awaitItem()
assertThat(initialState.urlState).isInstanceOf(Async.Success::class.java)
assertThat(initialState.urlState).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.isInWidgetMode).isTrue()
assertThat(widgetProvider.getWidgetCalled).isTrue()
assertThat(widgetDriver.runCalledCount).isEqualTo(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package io.element.android.features.createroom.api

import androidx.compose.runtime.MutableState
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId

Expand All @@ -27,5 +27,5 @@ interface StartDMAction {
* @param userId The user to start a DM with.
* @param actionState The state to update with the result of the action.
*/
suspend fun execute(userId: UserId, actionState: MutableState<Async<RoomId>>)
suspend fun execute(userId: UserId, actionState: MutableState<AsyncAction<RoomId>>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import androidx.compose.runtime.MutableState
import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.plan.CreatedRoom
import io.element.android.features.createroom.api.StartDMAction
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
Expand All @@ -36,17 +36,17 @@ class DefaultStartDMAction @Inject constructor(
private val analyticsService: AnalyticsService,
) : StartDMAction {

override suspend fun execute(userId: UserId, actionState: MutableState<Async<RoomId>>) {
actionState.value = Async.Loading()
override suspend fun execute(userId: UserId, actionState: MutableState<AsyncAction<RoomId>>) {
actionState.value = AsyncAction.Loading
when (val result = matrixClient.startDM(userId)) {
is StartDMResult.Success -> {
if (result.isNew) {
analyticsService.capture(CreatedRoom(isDM = true))
}
actionState.value = Async.Success(result.roomId)
actionState.value = AsyncAction.Success(result.roomId)
}
is StartDMResult.Failure -> {
actionState.value = Async.Failure(result.throwable)
actionState.value = AsyncAction.Failure(result.throwable)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import im.vector.app.features.analytics.plan.CreatedRoom
import io.element.android.features.createroom.impl.CreateRoomConfig
import io.element.android.features.createroom.impl.CreateRoomDataStore
import io.element.android.libraries.architecture.Async
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.core.mimetype.MimeTypes
Expand Down Expand Up @@ -91,10 +91,10 @@ class ConfigureRoomPresenter @Inject constructor(
}

val localCoroutineScope = rememberCoroutineScope()
val createRoomAction: MutableState<Async<RoomId>> = remember { mutableStateOf(Async.Uninitialized) }
val createRoomAction: MutableState<AsyncAction<RoomId>> = remember { mutableStateOf(AsyncAction.Uninitialized) }

fun createRoom(config: CreateRoomConfig) {
createRoomAction.value = Async.Uninitialized
createRoomAction.value = AsyncAction.Uninitialized
localCoroutineScope.createRoom(config, createRoomAction)
}

Expand All @@ -118,7 +118,7 @@ class ConfigureRoomPresenter @Inject constructor(
}
}

ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = Async.Uninitialized
ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = AsyncAction.Uninitialized
}
}

Expand All @@ -133,7 +133,7 @@ class ConfigureRoomPresenter @Inject constructor(

private fun CoroutineScope.createRoom(
config: CreateRoomConfig,
createRoomAction: MutableState<Async<RoomId>>
createRoomAction: MutableState<AsyncAction<RoomId>>
) = launch {
suspend {
val avatarUrl = config.avatarUri?.let { uploadAvatar(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@

package io.element.android.features.createroom.impl.configureroom

import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.features.createroom.impl.CreateRoomConfig
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.libraries.permissions.api.PermissionsState
import kotlinx.collections.immutable.ImmutableList

data class ConfigureRoomState(
val config: CreateRoomConfig,
val avatarActions: ImmutableList<AvatarAction>,
val createRoomAction: Async<RoomId>,
val createRoomAction: AsyncAction<RoomId>,
val cameraPermissionState: PermissionsState,
val eventSink: (ConfigureRoomEvents) -> Unit
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package io.element.android.features.createroom.impl.configureroom
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.createroom.impl.CreateRoomConfig
import io.element.android.features.createroom.impl.userlist.aListOfSelectedUsers
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.permissions.api.aPermissionsState
import kotlinx.collections.immutable.persistentListOf

Expand All @@ -41,7 +41,7 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomSt
fun aConfigureRoomState() = ConfigureRoomState(
config = CreateRoomConfig(),
avatarActions = persistentListOf(),
createRoomAction = Async.Uninitialized,
createRoomAction = AsyncAction.Uninitialized,
cameraPermissionState = aPermissionsState(showDialog = false),
eventSink = { },
)
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.features.createroom.impl.R
import io.element.android.features.createroom.impl.components.RoomPrivacyOption
import io.element.android.libraries.designsystem.components.LabelledTextField
import io.element.android.libraries.designsystem.components.async.AsyncView
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
Expand Down Expand Up @@ -148,9 +149,13 @@ fun ConfigureRoomView(
onActionSelected = { state.eventSink(ConfigureRoomEvents.HandleAvatarAction(it)) }
)

AsyncView(
AsyncActionView(
async = state.createRoomAction,
progressText = stringResource(CommonStrings.common_creating_room),
progressDialog = {
AsyncActionViewDefaults.ProgressDialog(
progressText = stringResource(CommonStrings.common_creating_room),
)
},
onSuccess = { onRoomCreated(it) },
errorMessage = { stringResource(R.string.screen_create_room_error_creating_room) },
onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom(state.config)) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import io.element.android.features.createroom.impl.userlist.SelectionMode
import io.element.android.features.createroom.impl.userlist.UserListDataStore
import io.element.android.features.createroom.impl.userlist.UserListPresenter
import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.core.RoomId
Expand Down Expand Up @@ -55,14 +55,14 @@ class CreateRoomRootPresenter @Inject constructor(
val userListState = presenter.present()

val localCoroutineScope = rememberCoroutineScope()
val startDmActionState: MutableState<Async<RoomId>> = remember { mutableStateOf(Async.Uninitialized) }
val startDmActionState: MutableState<AsyncAction<RoomId>> = remember { mutableStateOf(AsyncAction.Uninitialized) }

fun handleEvents(event: CreateRoomRootEvents) {
when (event) {
is CreateRoomRootEvents.StartDM -> localCoroutineScope.launch {
startDMAction.execute(event.matrixUser.userId, startDmActionState)
}
CreateRoomRootEvents.CancelStartDM -> startDmActionState.value = Async.Uninitialized
CreateRoomRootEvents.CancelStartDM -> startDmActionState.value = AsyncAction.Uninitialized
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
package io.element.android.features.createroom.impl.root

import io.element.android.features.createroom.impl.userlist.UserListState
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId

data class CreateRoomRootState(
val applicationName: String,
val userListState: UserListState,
val startDmAction: Async<RoomId>,
val startDmAction: AsyncAction<RoomId>,
val eventSink: (CreateRoomRootEvents) -> Unit,
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package io.element.android.features.createroom.impl.root

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.createroom.impl.userlist.aUserListState
import io.element.android.libraries.architecture.AsyncAction

import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.usersearch.api.UserSearchResult
Expand All @@ -30,7 +30,7 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
get() = sequenceOf(
aCreateRoomRootState(),
aCreateRoomRootState().copy(
startDmAction = Async.Loading(),
startDmAction = AsyncAction.Loading,
userListState = aMatrixUser().let {
aUserListState().copy(
searchQuery = it.userId.value,
Expand All @@ -41,7 +41,7 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
}
),
aCreateRoomRootState().copy(
startDmAction = Async.Failure(Throwable("error")),
startDmAction = AsyncAction.Failure(Throwable("error")),
userListState = aMatrixUser().let {
aUserListState().copy(
searchQuery = it.userId.value,
Expand All @@ -57,6 +57,6 @@ open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRoot
fun aCreateRoomRootState() = CreateRoomRootState(
eventSink = {},
applicationName = "Element X Preview",
startDmAction = Async.Uninitialized,
startDmAction = AsyncAction.Uninitialized,
userListState = aUserListState(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.createroom.impl.R
import io.element.android.features.createroom.impl.components.UserListView
import io.element.android.libraries.designsystem.components.async.AsyncView
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.icons.CompoundDrawables
import io.element.android.libraries.designsystem.preview.ElementPreview
Expand Down Expand Up @@ -93,9 +94,13 @@ fun CreateRoomRootView(
}
}

AsyncView(
AsyncActionView(
async = state.startDmAction,
progressText = stringResource(CommonStrings.common_starting_chat),
progressDialog = {
AsyncActionViewDefaults.ProgressDialog(
progressText = stringResource(CommonStrings.common_starting_chat),
)
},
onSuccess = { onOpenDM(it) },
errorMessage = { stringResource(R.string.screen_start_chat_error_starting_chat) },
onRetry = {
Expand Down
Loading

0 comments on commit 4948748

Please sign in to comment.