ganfra
4 months ago
13 changed files with 1 additions and 593 deletions
@ -1,26 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2023 New Vector Ltd |
|
||||||
* |
|
||||||
* 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 io.element.android.features.messages.impl.timeline.components.retrysendmenu |
|
||||||
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
|
||||||
|
|
||||||
sealed interface RetrySendMenuEvents { |
|
||||||
data class EventSelected(val event: TimelineItem.Event) : RetrySendMenuEvents |
|
||||||
data object Retry : RetrySendMenuEvents |
|
||||||
data object Remove : RetrySendMenuEvents |
|
||||||
data object Dismiss : RetrySendMenuEvents |
|
||||||
} |
|
@ -1,71 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2023 New Vector Ltd |
|
||||||
* |
|
||||||
* 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 io.element.android.features.messages.impl.timeline.components.retrysendmenu |
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable |
|
||||||
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 io.element.android.features.messages.impl.timeline.model.TimelineItem |
|
||||||
import io.element.android.libraries.architecture.Presenter |
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom |
|
||||||
import kotlinx.coroutines.launch |
|
||||||
import javax.inject.Inject |
|
||||||
|
|
||||||
class RetrySendMenuPresenter @Inject constructor( |
|
||||||
private val room: MatrixRoom, |
|
||||||
) : Presenter<RetrySendMenuState> { |
|
||||||
@Composable |
|
||||||
override fun present(): RetrySendMenuState { |
|
||||||
val coroutineScope = rememberCoroutineScope() |
|
||||||
var selectedEvent: TimelineItem.Event? by remember { mutableStateOf(null) } |
|
||||||
|
|
||||||
fun handleEvent(event: RetrySendMenuEvents) { |
|
||||||
when (event) { |
|
||||||
is RetrySendMenuEvents.EventSelected -> { |
|
||||||
selectedEvent = event.event |
|
||||||
} |
|
||||||
RetrySendMenuEvents.Retry -> { |
|
||||||
coroutineScope.launch { |
|
||||||
selectedEvent?.transactionId?.let { transactionId -> |
|
||||||
room.retrySendMessage(transactionId) |
|
||||||
} |
|
||||||
selectedEvent = null |
|
||||||
} |
|
||||||
} |
|
||||||
RetrySendMenuEvents.Remove -> { |
|
||||||
coroutineScope.launch { |
|
||||||
selectedEvent?.transactionId?.let { transactionId -> |
|
||||||
room.cancelSend(transactionId) |
|
||||||
} |
|
||||||
selectedEvent = null |
|
||||||
} |
|
||||||
} |
|
||||||
RetrySendMenuEvents.Dismiss -> { |
|
||||||
selectedEvent = null |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return RetrySendMenuState( |
|
||||||
selectedEvent = selectedEvent, |
|
||||||
eventSink = { handleEvent(it) }, |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
@ -1,26 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2023 New Vector Ltd |
|
||||||
* |
|
||||||
* 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 io.element.android.features.messages.impl.timeline.components.retrysendmenu |
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable |
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
|
||||||
|
|
||||||
@Immutable |
|
||||||
data class RetrySendMenuState( |
|
||||||
val selectedEvent: TimelineItem.Event?, |
|
||||||
val eventSink: (RetrySendMenuEvents) -> Unit, |
|
||||||
) |
|
@ -1,36 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2023 New Vector Ltd |
|
||||||
* |
|
||||||
* 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 io.element.android.features.messages.impl.timeline.components.retrysendmenu |
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider |
|
||||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent |
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
|
||||||
|
|
||||||
class RetrySendMenuStateProvider : PreviewParameterProvider<RetrySendMenuState> { |
|
||||||
override val values: Sequence<RetrySendMenuState> = sequenceOf( |
|
||||||
aRetrySendMenuState(), |
|
||||||
aRetrySendMenuState(event = aTimelineItemEvent()), |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
fun aRetrySendMenuState( |
|
||||||
event: TimelineItem.Event? = null, |
|
||||||
eventSink: (RetrySendMenuEvents) -> Unit = {}, |
|
||||||
) = RetrySendMenuState( |
|
||||||
selectedEvent = event, |
|
||||||
eventSink = eventSink, |
|
||||||
) |
|
@ -1,159 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2023 New Vector Ltd |
|
||||||
* |
|
||||||
* 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 io.element.android.features.messages.impl.timeline.components.retrysendmenu |
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable |
|
||||||
import androidx.compose.foundation.layout.ColumnScope |
|
||||||
import androidx.compose.foundation.layout.Spacer |
|
||||||
import androidx.compose.foundation.layout.height |
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api |
|
||||||
import androidx.compose.material3.ListItem |
|
||||||
import androidx.compose.material3.ListItemDefaults |
|
||||||
import androidx.compose.material3.MaterialTheme |
|
||||||
import androidx.compose.material3.SheetState |
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState |
|
||||||
import androidx.compose.runtime.Composable |
|
||||||
import androidx.compose.runtime.rememberCoroutineScope |
|
||||||
import androidx.compose.ui.Modifier |
|
||||||
import androidx.compose.ui.res.stringResource |
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter |
|
||||||
import androidx.compose.ui.unit.dp |
|
||||||
import io.element.android.compound.theme.ElementTheme |
|
||||||
import io.element.android.features.messages.impl.R |
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview |
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight |
|
||||||
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet |
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text |
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings |
|
||||||
import kotlinx.coroutines.launch |
|
||||||
|
|
||||||
@Composable |
|
||||||
internal fun RetrySendMessageMenu( |
|
||||||
state: RetrySendMenuState, |
|
||||||
modifier: Modifier = Modifier, |
|
||||||
) { |
|
||||||
val isVisible = state.selectedEvent != null |
|
||||||
|
|
||||||
fun onDismiss() { |
|
||||||
state.eventSink(RetrySendMenuEvents.Dismiss) |
|
||||||
} |
|
||||||
|
|
||||||
fun onRetry() { |
|
||||||
state.eventSink(RetrySendMenuEvents.Retry) |
|
||||||
} |
|
||||||
|
|
||||||
fun onRemove() { |
|
||||||
state.eventSink(RetrySendMenuEvents.Remove) |
|
||||||
} |
|
||||||
|
|
||||||
RetrySendMessageMenuBottomSheet( |
|
||||||
modifier = modifier, |
|
||||||
isVisible = isVisible, |
|
||||||
onRetry = ::onRetry, |
|
||||||
onRemove = ::onRemove, |
|
||||||
onDismiss = ::onDismiss |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class) |
|
||||||
@Composable |
|
||||||
private fun RetrySendMessageMenuBottomSheet( |
|
||||||
isVisible: Boolean, |
|
||||||
onRetry: () -> Unit, |
|
||||||
onRemove: () -> Unit, |
|
||||||
onDismiss: () -> Unit, |
|
||||||
modifier: Modifier = Modifier, |
|
||||||
) { |
|
||||||
val sheetState = rememberModalBottomSheetState() |
|
||||||
val coroutineScope = rememberCoroutineScope() |
|
||||||
|
|
||||||
if (isVisible) { |
|
||||||
ModalBottomSheet( |
|
||||||
modifier = modifier, |
|
||||||
// modifier = modifier.navigationBarsPadding() - FIXME after https://issuetracker.google.com/issues/275849044 |
|
||||||
// .imePadding() |
|
||||||
sheetState = sheetState, |
|
||||||
onDismissRequest = { |
|
||||||
coroutineScope.launch { |
|
||||||
sheetState.hide() |
|
||||||
onDismiss() |
|
||||||
} |
|
||||||
} |
|
||||||
) { |
|
||||||
RetrySendMenuContents( |
|
||||||
onRetry = onRetry, |
|
||||||
onRemove = onRemove, |
|
||||||
) |
|
||||||
// FIXME remove after https://issuetracker.google.com/issues/275849044 |
|
||||||
Spacer(modifier = Modifier.height(32.dp)) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class) |
|
||||||
@Composable |
|
||||||
private fun ColumnScope.RetrySendMenuContents( |
|
||||||
onRetry: () -> Unit, |
|
||||||
onRemove: () -> Unit, |
|
||||||
sheetState: SheetState = rememberModalBottomSheetState(), |
|
||||||
) { |
|
||||||
val coroutineScope = rememberCoroutineScope() |
|
||||||
|
|
||||||
ListItem(headlineContent = { |
|
||||||
Text( |
|
||||||
text = stringResource(R.string.screen_room_retry_send_menu_title), |
|
||||||
style = ElementTheme.typography.fontBodyLgMedium, |
|
||||||
) |
|
||||||
}) |
|
||||||
ListItem( |
|
||||||
headlineContent = { |
|
||||||
Text( |
|
||||||
text = stringResource(R.string.screen_room_retry_send_menu_send_again_action), |
|
||||||
style = ElementTheme.typography.fontBodyLgRegular, |
|
||||||
) |
|
||||||
}, |
|
||||||
modifier = Modifier.clickable { |
|
||||||
coroutineScope.launch { |
|
||||||
sheetState.hide() |
|
||||||
onRetry() |
|
||||||
} |
|
||||||
} |
|
||||||
) |
|
||||||
ListItem( |
|
||||||
headlineContent = { |
|
||||||
Text( |
|
||||||
text = stringResource(CommonStrings.action_remove), |
|
||||||
style = ElementTheme.typography.fontBodyLgRegular, |
|
||||||
) |
|
||||||
}, |
|
||||||
colors = ListItemDefaults.colors(headlineColor = MaterialTheme.colorScheme.error), |
|
||||||
modifier = Modifier.clickable { |
|
||||||
coroutineScope.launch { |
|
||||||
sheetState.hide() |
|
||||||
onRemove() |
|
||||||
} |
|
||||||
} |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
@PreviewsDayNight |
|
||||||
@Composable |
|
||||||
internal fun RetrySendMessageMenuPreview(@PreviewParameter(RetrySendMenuStateProvider::class) state: RetrySendMenuState) = ElementPreview { |
|
||||||
RetrySendMessageMenu( |
|
||||||
state = state, |
|
||||||
) |
|
||||||
} |
|
@ -1,163 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2023 New Vector Ltd |
|
||||||
* |
|
||||||
* 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 io.element.android.features.messages.impl.timeline.components.retrysendmenu |
|
||||||
|
|
||||||
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.features.messages.impl.timeline.aTimelineItemEvent |
|
||||||
import io.element.android.libraries.matrix.test.A_TRANSACTION_ID |
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom |
|
||||||
import io.element.android.tests.testutils.WarmUpRule |
|
||||||
import kotlinx.coroutines.test.runTest |
|
||||||
import org.junit.Rule |
|
||||||
import org.junit.Test |
|
||||||
|
|
||||||
class RetrySendMenuPresenterTest { |
|
||||||
@get:Rule |
|
||||||
val warmUpRule = WarmUpRule() |
|
||||||
|
|
||||||
private val room = FakeMatrixRoom() |
|
||||||
private val presenter = RetrySendMenuPresenter(room) |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle event selected`() = runTest { |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent() |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
assertThat(awaitItem().selectedEvent).isSameInstanceAs(selectedEvent) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle dismiss`() = runTest { |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent() |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
skipItems(1) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.Dismiss) |
|
||||||
assertThat(room.cancelSendCount).isEqualTo(0) |
|
||||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
|
||||||
assertThat(awaitItem().selectedEvent).isNull() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle resend with transactionId`() = runTest { |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
skipItems(1) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.Retry) |
|
||||||
assertThat(room.cancelSendCount).isEqualTo(0) |
|
||||||
assertThat(room.retrySendMessageCount).isEqualTo(1) |
|
||||||
assertThat(awaitItem().selectedEvent).isNull() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle resend without transactionId`() = runTest { |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent(transactionId = null) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
skipItems(1) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.Retry) |
|
||||||
assertThat(room.cancelSendCount).isEqualTo(0) |
|
||||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
|
||||||
assertThat(awaitItem().selectedEvent).isNull() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle resend with error`() = runTest { |
|
||||||
room.givenRetrySendMessageResult(Result.failure(IllegalStateException("An error"))) |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
skipItems(1) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.Retry) |
|
||||||
assertThat(room.cancelSendCount).isEqualTo(0) |
|
||||||
assertThat(room.retrySendMessageCount).isEqualTo(1) |
|
||||||
assertThat(awaitItem().selectedEvent).isNull() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle remove failed message with transactionId`() = runTest { |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
skipItems(1) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.Remove) |
|
||||||
assertThat(room.cancelSendCount).isEqualTo(1) |
|
||||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
|
||||||
assertThat(awaitItem().selectedEvent).isNull() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle remove failed message without transactionId`() = runTest { |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent(transactionId = null) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
skipItems(1) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.Remove) |
|
||||||
assertThat(room.cancelSendCount).isEqualTo(0) |
|
||||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
|
||||||
assertThat(awaitItem().selectedEvent).isNull() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `present - handle remove failed message with error`() = runTest { |
|
||||||
room.givenRetrySendMessageResult(Result.failure(IllegalStateException("An error"))) |
|
||||||
moleculeFlow(RecompositionMode.Immediate) { |
|
||||||
presenter.present() |
|
||||||
}.test { |
|
||||||
val initialState = awaitItem() |
|
||||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
|
||||||
skipItems(1) |
|
||||||
initialState.eventSink(RetrySendMenuEvents.Remove) |
|
||||||
assertThat(room.cancelSendCount).isEqualTo(1) |
|
||||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
|
||||||
assertThat(awaitItem().selectedEvent).isNull() |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,90 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2024 New Vector Ltd |
|
||||||
* |
|
||||||
* 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 io.element.android.features.messages.impl.timeline.components.retrysendmenu |
|
||||||
|
|
||||||
import androidx.activity.ComponentActivity |
|
||||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule |
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule |
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4 |
|
||||||
import io.element.android.features.messages.impl.R |
|
||||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent |
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings |
|
||||||
import io.element.android.tests.testutils.EventsRecorder |
|
||||||
import io.element.android.tests.testutils.clickOn |
|
||||||
import io.element.android.tests.testutils.pressBackKey |
|
||||||
import org.junit.Rule |
|
||||||
import org.junit.Test |
|
||||||
import org.junit.rules.TestRule |
|
||||||
import org.junit.runner.RunWith |
|
||||||
import org.robolectric.annotation.Config |
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class) |
|
||||||
class RetrySendMessageMenuTest { |
|
||||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>() |
|
||||||
|
|
||||||
@Test |
|
||||||
fun `dismiss the bottom sheet emits the expected event`() { |
|
||||||
val eventsRecorder = EventsRecorder<RetrySendMenuEvents>() |
|
||||||
rule.setRetrySendMessageMenu( |
|
||||||
aRetrySendMenuState( |
|
||||||
event = aTimelineItemEvent(), |
|
||||||
eventSink = eventsRecorder |
|
||||||
), |
|
||||||
) |
|
||||||
rule.pressBackKey() |
|
||||||
// Cannot test this for now. |
|
||||||
// eventsRecorder.assertSingle(RetrySendMenuEvents.Dismiss) |
|
||||||
} |
|
||||||
|
|
||||||
@Config(qualifiers = "h1024dp") |
|
||||||
@Test |
|
||||||
fun `retry to send the event emits the expected event`() { |
|
||||||
val eventsRecorder = EventsRecorder<RetrySendMenuEvents>() |
|
||||||
rule.setRetrySendMessageMenu( |
|
||||||
aRetrySendMenuState( |
|
||||||
event = aTimelineItemEvent(), |
|
||||||
eventSink = eventsRecorder |
|
||||||
), |
|
||||||
) |
|
||||||
rule.clickOn(R.string.screen_room_retry_send_menu_send_again_action) |
|
||||||
eventsRecorder.assertSingle(RetrySendMenuEvents.Retry) |
|
||||||
} |
|
||||||
|
|
||||||
@Config(qualifiers = "h1024dp") |
|
||||||
@Test |
|
||||||
fun `remove the event emits the expected event`() { |
|
||||||
val eventsRecorder = EventsRecorder<RetrySendMenuEvents>() |
|
||||||
rule.setRetrySendMessageMenu( |
|
||||||
aRetrySendMenuState( |
|
||||||
event = aTimelineItemEvent(), |
|
||||||
eventSink = eventsRecorder |
|
||||||
), |
|
||||||
) |
|
||||||
rule.clickOn(CommonStrings.action_remove) |
|
||||||
eventsRecorder.assertSingle(RetrySendMenuEvents.Remove) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRetrySendMessageMenu( |
|
||||||
state: RetrySendMenuState, |
|
||||||
) { |
|
||||||
setContent { |
|
||||||
RetrySendMessageMenu( |
|
||||||
state = state, |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue