Merge pull request #6097 from element-hq/feature/bma/favoriteWording
Improve favorite wording and icon of room
This commit is contained in:
@@ -10,7 +10,7 @@ package io.element.android.features.home.impl
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
|
||||
sealed interface HomeEvents {
|
||||
data class SelectHomeNavigationBarItem(val item: HomeNavigationBarItem) : HomeEvents
|
||||
data class SwitchToAccount(val sessionId: SessionId) : HomeEvents
|
||||
sealed interface HomeEvent {
|
||||
data class SelectHomeNavigationBarItem(val item: HomeNavigationBarItem) : HomeEvent
|
||||
data class SwitchToAccount(val sessionId: SessionId) : HomeEvent
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.home.api.HomeEntryPoint
|
||||
import io.element.android.features.home.impl.components.RoomListMenuAction
|
||||
import io.element.android.features.home.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvents
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvent
|
||||
import io.element.android.features.invite.api.InviteData
|
||||
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteView
|
||||
import io.element.android.features.invite.api.declineandblock.DeclineInviteAndBlockEntryPoint
|
||||
@@ -159,7 +159,7 @@ class HomeFlowNode(
|
||||
}
|
||||
|
||||
private fun onNewOwnersSelected(roomId: RoomId) {
|
||||
stateFlow.value.roomListState.eventSink(RoomListEvents.LeaveRoom(roomId, needsConfirmation = false))
|
||||
stateFlow.value.roomListState.eventSink(RoomListEvent.LeaveRoom(roomId, needsConfirmation = false))
|
||||
}
|
||||
|
||||
private fun rootNode(buildContext: BuildContext): Node {
|
||||
|
||||
@@ -80,15 +80,15 @@ class HomePresenter(
|
||||
val showAvatarIndicator by indicatorService.showRoomListTopBarIndicator()
|
||||
val directLogoutState = logoutPresenter.present()
|
||||
|
||||
fun handleEvent(event: HomeEvents) {
|
||||
fun handleEvent(event: HomeEvent) {
|
||||
when (event) {
|
||||
is HomeEvents.SelectHomeNavigationBarItem -> coroutineState.launch {
|
||||
is HomeEvent.SelectHomeNavigationBarItem -> coroutineState.launch {
|
||||
if (event.item == HomeNavigationBarItem.Spaces) {
|
||||
announcementService.showAnnouncement(Announcement.Space)
|
||||
}
|
||||
currentHomeNavigationBarItemOrdinal = event.item.ordinal
|
||||
}
|
||||
is HomeEvents.SwitchToAccount -> coroutineState.launch {
|
||||
is HomeEvent.SwitchToAccount -> coroutineState.launch {
|
||||
sessionStore.setLatestSession(event.sessionId.value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ data class HomeState(
|
||||
val snackbarMessage: SnackbarMessage?,
|
||||
val canReportBug: Boolean,
|
||||
val directLogoutState: DirectLogoutState,
|
||||
val eventSink: (HomeEvents) -> Unit,
|
||||
val eventSink: (HomeEvent) -> Unit,
|
||||
) {
|
||||
val displayActions = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats
|
||||
val displayRoomListFilters = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats && roomListState.displayFilters
|
||||
|
||||
@@ -59,7 +59,7 @@ internal fun aHomeState(
|
||||
homeSpacesState: HomeSpacesState = aHomeSpacesState(),
|
||||
canReportBug: Boolean = true,
|
||||
directLogoutState: DirectLogoutState = aDirectLogoutState(),
|
||||
eventSink: (HomeEvents) -> Unit = {}
|
||||
eventSink: (HomeEvent) -> Unit = {}
|
||||
) = HomeState(
|
||||
currentUserAndNeighbors = currentUserAndNeighbors.toImmutableList(),
|
||||
showAvatarIndicator = showAvatarIndicator,
|
||||
|
||||
@@ -47,7 +47,7 @@ import io.element.android.features.home.impl.components.RoomListMenuAction
|
||||
import io.element.android.features.home.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.home.impl.roomlist.RoomListContextMenu
|
||||
import io.element.android.features.home.impl.roomlist.RoomListDeclineInviteMenu
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvents
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvent
|
||||
import io.element.android.features.home.impl.roomlist.RoomListState
|
||||
import io.element.android.features.home.impl.search.RoomListSearchView
|
||||
import io.element.android.features.home.impl.spaces.HomeSpacesView
|
||||
@@ -156,7 +156,7 @@ private fun HomeScaffold(
|
||||
BackHandler(
|
||||
enabled = state.currentHomeNavigationBarItem != HomeNavigationBarItem.Chats,
|
||||
) {
|
||||
state.eventSink(HomeEvents.SelectHomeNavigationBarItem(HomeNavigationBarItem.Chats))
|
||||
state.eventSink(HomeEvent.SelectHomeNavigationBarItem(HomeNavigationBarItem.Chats))
|
||||
}
|
||||
|
||||
val hazeState = rememberHazeState()
|
||||
@@ -172,11 +172,11 @@ private fun HomeScaffold(
|
||||
currentUserAndNeighbors = state.currentUserAndNeighbors,
|
||||
showAvatarIndicator = state.showAvatarIndicator,
|
||||
areSearchResultsDisplayed = roomListState.searchState.isSearchActive,
|
||||
onToggleSearch = { roomListState.eventSink(RoomListEvents.ToggleSearchResults) },
|
||||
onToggleSearch = { roomListState.eventSink(RoomListEvent.ToggleSearchResults) },
|
||||
onMenuActionClick = onMenuActionClick,
|
||||
onOpenSettings = onOpenSettings,
|
||||
onAccountSwitch = {
|
||||
state.eventSink(HomeEvents.SwitchToAccount(it))
|
||||
state.eventSink(HomeEvent.SwitchToAccount(it))
|
||||
},
|
||||
onCreateSpace = onCreateSpaceClick,
|
||||
scrollBehavior = scrollBehavior,
|
||||
@@ -211,7 +211,7 @@ private fun HomeScaffold(
|
||||
lazyListStateTarget.animateScrollToItem(0)
|
||||
}
|
||||
} else {
|
||||
state.eventSink(HomeEvents.SelectHomeNavigationBarItem(item))
|
||||
state.eventSink(HomeEvent.SelectHomeNavigationBarItem(item))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.hazeEffect(
|
||||
|
||||
@@ -47,7 +47,7 @@ import io.element.android.features.home.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.home.impl.model.RoomSummaryDisplayType
|
||||
import io.element.android.features.home.impl.roomlist.RoomListContentState
|
||||
import io.element.android.features.home.impl.roomlist.RoomListContentStateProvider
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvents
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvent
|
||||
import io.element.android.features.home.impl.roomlist.SecurityBannerState
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
@@ -64,7 +64,7 @@ fun RoomListContentView(
|
||||
filtersState: RoomListFiltersState,
|
||||
lazyListState: LazyListState,
|
||||
hideInvitesAvatars: Boolean,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
onSetUpRecoveryClick: () -> Unit,
|
||||
onConfirmRecoveryKeyClick: () -> Unit,
|
||||
onRoomClick: (RoomListRoomSummary) -> Unit,
|
||||
@@ -131,7 +131,7 @@ private fun SkeletonView(
|
||||
@Composable
|
||||
private fun EmptyView(
|
||||
state: RoomListContentState.Empty,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
onSetUpRecoveryClick: () -> Unit,
|
||||
onConfirmRecoveryKeyClick: () -> Unit,
|
||||
onCreateRoomClick: () -> Unit,
|
||||
@@ -155,13 +155,13 @@ private fun EmptyView(
|
||||
SecurityBannerState.SetUpRecovery -> {
|
||||
SetUpRecoveryKeyBanner(
|
||||
onContinueClick = onSetUpRecoveryClick,
|
||||
onDismissClick = { eventSink(RoomListEvents.DismissBanner) },
|
||||
onDismissClick = { eventSink(RoomListEvent.DismissBanner) },
|
||||
)
|
||||
}
|
||||
SecurityBannerState.RecoveryKeyConfirmation -> {
|
||||
ConfirmRecoveryKeyBanner(
|
||||
onContinueClick = onConfirmRecoveryKeyClick,
|
||||
onDismissClick = { eventSink(RoomListEvents.DismissBanner) },
|
||||
onDismissClick = { eventSink(RoomListEvent.DismissBanner) },
|
||||
)
|
||||
}
|
||||
SecurityBannerState.None -> Unit
|
||||
@@ -175,7 +175,7 @@ private fun RoomsView(
|
||||
state: RoomListContentState.Rooms,
|
||||
hideInvitesAvatars: Boolean,
|
||||
filtersState: RoomListFiltersState,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
onSetUpRecoveryClick: () -> Unit,
|
||||
onConfirmRecoveryKeyClick: () -> Unit,
|
||||
onRoomClick: (RoomListRoomSummary) -> Unit,
|
||||
@@ -207,7 +207,7 @@ private fun RoomsView(
|
||||
private fun RoomsViewList(
|
||||
state: RoomListContentState.Rooms,
|
||||
hideInvitesAvatars: Boolean,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
onSetUpRecoveryClick: () -> Unit,
|
||||
onConfirmRecoveryKeyClick: () -> Unit,
|
||||
onRoomClick: (RoomListRoomSummary) -> Unit,
|
||||
@@ -225,7 +225,7 @@ private fun RoomsViewList(
|
||||
}
|
||||
val updatedEventSink by rememberUpdatedState(newValue = eventSink)
|
||||
LaunchedEffect(visibleRange) {
|
||||
updatedEventSink(RoomListEvents.UpdateVisibleRange(visibleRange))
|
||||
updatedEventSink(RoomListEvent.UpdateVisibleRange(visibleRange))
|
||||
}
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
@@ -237,7 +237,7 @@ private fun RoomsViewList(
|
||||
item {
|
||||
SetUpRecoveryKeyBanner(
|
||||
onContinueClick = onSetUpRecoveryClick,
|
||||
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) },
|
||||
onDismissClick = { updatedEventSink(RoomListEvent.DismissBanner) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -245,7 +245,7 @@ private fun RoomsViewList(
|
||||
item {
|
||||
ConfirmRecoveryKeyBanner(
|
||||
onContinueClick = onConfirmRecoveryKeyClick,
|
||||
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) },
|
||||
onDismissClick = { updatedEventSink(RoomListEvent.DismissBanner) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ private fun RoomsViewList(
|
||||
} else if (state.showNewNotificationSoundBanner) {
|
||||
item {
|
||||
NewNotificationSoundBanner(
|
||||
onDismissClick = { updatedEventSink(RoomListEvents.DismissNewNotificationSoundBanner) },
|
||||
onDismissClick = { updatedEventSink(RoomListEvent.DismissNewNotificationSoundBanner) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ import io.element.android.features.home.impl.model.LatestEvent
|
||||
import io.element.android.features.home.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.home.impl.model.RoomListRoomSummaryProvider
|
||||
import io.element.android.features.home.impl.model.RoomSummaryDisplayType
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvents
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvent
|
||||
import io.element.android.libraries.core.extensions.orEmpty
|
||||
import io.element.android.libraries.core.extensions.toSafeLength
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom
|
||||
@@ -74,7 +74,7 @@ internal fun RoomSummaryRow(
|
||||
hideInviteAvatars: Boolean,
|
||||
isInviteSeen: Boolean,
|
||||
onClick: (RoomListRoomSummary) -> Unit,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
@@ -104,10 +104,10 @@ internal fun RoomSummaryRow(
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
InviteButtonsRowMolecule(
|
||||
onAcceptClick = {
|
||||
eventSink(RoomListEvents.AcceptInvite(room))
|
||||
eventSink(RoomListEvent.AcceptInvite(room))
|
||||
},
|
||||
onDeclineClick = {
|
||||
eventSink(RoomListEvents.ShowDeclineInviteMenu(room))
|
||||
eventSink(RoomListEvent.ShowDeclineInviteMenu(room))
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -117,7 +117,7 @@ internal fun RoomSummaryRow(
|
||||
room = room,
|
||||
onClick = onClick,
|
||||
onLongClick = {
|
||||
eventSink(RoomListEvents.ShowContextMenu(room))
|
||||
eventSink(RoomListEvent.ShowContextMenu(room))
|
||||
},
|
||||
) {
|
||||
NameAndTimestampRow(
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
package io.element.android.features.home.impl.filters
|
||||
|
||||
sealed interface RoomListFiltersEvents {
|
||||
data class ToggleFilter(val filter: RoomListFilter) : RoomListFiltersEvents
|
||||
data object ClearSelectedFilters : RoomListFiltersEvents
|
||||
sealed interface RoomListFiltersEvent {
|
||||
data class ToggleFilter(val filter: RoomListFilter) : RoomListFiltersEvent
|
||||
data object ClearSelectedFilters : RoomListFiltersEvent
|
||||
}
|
||||
@@ -28,12 +28,12 @@ class RoomListFiltersPresenter(
|
||||
|
||||
@Composable
|
||||
override fun present(): RoomListFiltersState {
|
||||
fun handleEvent(event: RoomListFiltersEvents) {
|
||||
fun handleEvent(event: RoomListFiltersEvent) {
|
||||
when (event) {
|
||||
RoomListFiltersEvents.ClearSelectedFilters -> {
|
||||
RoomListFiltersEvent.ClearSelectedFilters -> {
|
||||
filterSelectionStrategy.clear()
|
||||
}
|
||||
is RoomListFiltersEvents.ToggleFilter -> {
|
||||
is RoomListFiltersEvent.ToggleFilter -> {
|
||||
filterSelectionStrategy.toggle(event.filter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
data class RoomListFiltersState(
|
||||
val filterSelectionStates: ImmutableList<FilterSelectionState>,
|
||||
val eventSink: (RoomListFiltersEvents) -> Unit,
|
||||
val eventSink: (RoomListFiltersEvent) -> Unit,
|
||||
) {
|
||||
val hasAnyFilterSelected = filterSelectionStates.any { it.isSelected }
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class RoomListFiltersStateProvider : PreviewParameterProvider<RoomListFiltersSta
|
||||
|
||||
fun aRoomListFiltersState(
|
||||
filterSelectionStates: List<FilterSelectionState> = RoomListFilter.entries.map { FilterSelectionState(it, isSelected = false) },
|
||||
eventSink: (RoomListFiltersEvents) -> Unit = {},
|
||||
eventSink: (RoomListFiltersEvent) -> Unit = {},
|
||||
) = RoomListFiltersState(
|
||||
filterSelectionStates = filterSelectionStates.toImmutableList(),
|
||||
eventSink = eventSink,
|
||||
|
||||
@@ -60,11 +60,11 @@ fun RoomListFiltersView(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
fun onClearFiltersClick() {
|
||||
state.eventSink(RoomListFiltersEvents.ClearSelectedFilters)
|
||||
state.eventSink(RoomListFiltersEvent.ClearSelectedFilters)
|
||||
}
|
||||
|
||||
fun onToggleFilter(filter: RoomListFilter) {
|
||||
state.eventSink(RoomListFiltersEvents.ToggleFilter(filter))
|
||||
state.eventSink(RoomListFiltersEvent.ToggleFilter(filter))
|
||||
}
|
||||
|
||||
var scrollToStart by remember { mutableIntStateOf(0) }
|
||||
|
||||
@@ -37,41 +37,41 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||
fun RoomListContextMenu(
|
||||
contextMenu: RoomListState.ContextMenu.Shown,
|
||||
canReportRoom: Boolean,
|
||||
eventSink: (RoomListEvents.ContextMenuEvents) -> Unit,
|
||||
eventSink: (RoomListEvent.ContextMenuEvent) -> Unit,
|
||||
onRoomSettingsClick: (roomId: RoomId) -> Unit,
|
||||
onReportRoomClick: (roomId: RoomId) -> Unit
|
||||
) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { eventSink(RoomListEvents.HideContextMenu) },
|
||||
onDismissRequest = { eventSink(RoomListEvent.HideContextMenu) },
|
||||
) {
|
||||
RoomListModalBottomSheetContent(
|
||||
contextMenu = contextMenu,
|
||||
canReportRoom = canReportRoom,
|
||||
onRoomMarkReadClick = {
|
||||
eventSink(RoomListEvents.HideContextMenu)
|
||||
eventSink(RoomListEvents.MarkAsRead(contextMenu.roomId))
|
||||
eventSink(RoomListEvent.HideContextMenu)
|
||||
eventSink(RoomListEvent.MarkAsRead(contextMenu.roomId))
|
||||
},
|
||||
onRoomMarkUnreadClick = {
|
||||
eventSink(RoomListEvents.HideContextMenu)
|
||||
eventSink(RoomListEvents.MarkAsUnread(contextMenu.roomId))
|
||||
eventSink(RoomListEvent.HideContextMenu)
|
||||
eventSink(RoomListEvent.MarkAsUnread(contextMenu.roomId))
|
||||
},
|
||||
onRoomSettingsClick = {
|
||||
eventSink(RoomListEvents.HideContextMenu)
|
||||
eventSink(RoomListEvent.HideContextMenu)
|
||||
onRoomSettingsClick(contextMenu.roomId)
|
||||
},
|
||||
onLeaveRoomClick = {
|
||||
eventSink(RoomListEvents.HideContextMenu)
|
||||
eventSink(RoomListEvents.LeaveRoom(contextMenu.roomId, needsConfirmation = true))
|
||||
eventSink(RoomListEvent.HideContextMenu)
|
||||
eventSink(RoomListEvent.LeaveRoom(contextMenu.roomId, needsConfirmation = true))
|
||||
},
|
||||
onFavoriteChange = { isFavorite ->
|
||||
eventSink(RoomListEvents.SetRoomIsFavorite(contextMenu.roomId, isFavorite))
|
||||
eventSink(RoomListEvent.SetRoomIsFavorite(contextMenu.roomId, isFavorite))
|
||||
},
|
||||
onClearCacheRoomClick = {
|
||||
eventSink(RoomListEvents.HideContextMenu)
|
||||
eventSink(RoomListEvents.ClearCacheOfRoom(contextMenu.roomId))
|
||||
eventSink(RoomListEvent.HideContextMenu)
|
||||
eventSink(RoomListEvent.ClearCacheOfRoom(contextMenu.roomId))
|
||||
},
|
||||
onReportRoomClick = {
|
||||
eventSink(RoomListEvents.HideContextMenu)
|
||||
eventSink(RoomListEvent.HideContextMenu)
|
||||
onReportRoomClick(contextMenu.roomId)
|
||||
},
|
||||
)
|
||||
@@ -131,16 +131,21 @@ private fun RoomListModalBottomSheetContent(
|
||||
style = ListItemStyle.Primary,
|
||||
)
|
||||
}
|
||||
val (textResId, icon) = if (contextMenu.isFavorite) {
|
||||
CommonStrings.common_favourited to CompoundIcons.FavouriteSolid()
|
||||
} else {
|
||||
CommonStrings.common_favourite to CompoundIcons.Favourite()
|
||||
}
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(id = CommonStrings.common_favourite),
|
||||
text = stringResource(id = textResId),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
},
|
||||
leadingContent = ListItemContent.Icon(
|
||||
iconSource = IconSource.Vector(
|
||||
CompoundIcons.Favourite(),
|
||||
icon,
|
||||
)
|
||||
),
|
||||
trailingContent = ListItemContent.Switch(
|
||||
|
||||
@@ -38,27 +38,27 @@ fun RoomListDeclineInviteMenu(
|
||||
menu: RoomListState.DeclineInviteMenu.Shown,
|
||||
canReportRoom: Boolean,
|
||||
onDeclineAndBlockClick: (RoomListRoomSummary) -> Unit,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { eventSink(RoomListEvents.HideDeclineInviteMenu) },
|
||||
onDismissRequest = { eventSink(RoomListEvent.HideDeclineInviteMenu) },
|
||||
) {
|
||||
RoomListDeclineInviteMenuContent(
|
||||
roomName = menu.roomSummary.name ?: menu.roomSummary.roomId.value,
|
||||
onDeclineClick = {
|
||||
eventSink(RoomListEvents.HideDeclineInviteMenu)
|
||||
eventSink(RoomListEvents.DeclineInvite(menu.roomSummary, false))
|
||||
eventSink(RoomListEvent.HideDeclineInviteMenu)
|
||||
eventSink(RoomListEvent.DeclineInvite(menu.roomSummary, false))
|
||||
},
|
||||
onDeclineAndBlockClick = {
|
||||
eventSink(RoomListEvents.HideDeclineInviteMenu)
|
||||
eventSink(RoomListEvent.HideDeclineInviteMenu)
|
||||
if (canReportRoom) {
|
||||
onDeclineAndBlockClick(menu.roomSummary)
|
||||
} else {
|
||||
eventSink(RoomListEvents.DeclineInvite(menu.roomSummary, true))
|
||||
eventSink(RoomListEvent.DeclineInvite(menu.roomSummary, true))
|
||||
}
|
||||
},
|
||||
onCancelClick = {
|
||||
eventSink(RoomListEvents.HideDeclineInviteMenu)
|
||||
eventSink(RoomListEvent.HideDeclineInviteMenu)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,24 +11,24 @@ package io.element.android.features.home.impl.roomlist
|
||||
import io.element.android.features.home.impl.model.RoomListRoomSummary
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
sealed interface RoomListEvents {
|
||||
data class UpdateVisibleRange(val range: IntRange) : RoomListEvents
|
||||
data object DismissRequestVerificationPrompt : RoomListEvents
|
||||
data object DismissBanner : RoomListEvents
|
||||
data object DismissNewNotificationSoundBanner : RoomListEvents
|
||||
data object ToggleSearchResults : RoomListEvents
|
||||
data class ShowContextMenu(val roomSummary: RoomListRoomSummary) : RoomListEvents
|
||||
sealed interface RoomListEvent {
|
||||
data class UpdateVisibleRange(val range: IntRange) : RoomListEvent
|
||||
data object DismissRequestVerificationPrompt : RoomListEvent
|
||||
data object DismissBanner : RoomListEvent
|
||||
data object DismissNewNotificationSoundBanner : RoomListEvent
|
||||
data object ToggleSearchResults : RoomListEvent
|
||||
data class ShowContextMenu(val roomSummary: RoomListRoomSummary) : RoomListEvent
|
||||
|
||||
data class AcceptInvite(val roomSummary: RoomListRoomSummary) : RoomListEvents
|
||||
data class DeclineInvite(val roomSummary: RoomListRoomSummary, val blockUser: Boolean) : RoomListEvents
|
||||
data class ShowDeclineInviteMenu(val roomSummary: RoomListRoomSummary) : RoomListEvents
|
||||
data object HideDeclineInviteMenu : RoomListEvents
|
||||
data class AcceptInvite(val roomSummary: RoomListRoomSummary) : RoomListEvent
|
||||
data class DeclineInvite(val roomSummary: RoomListRoomSummary, val blockUser: Boolean) : RoomListEvent
|
||||
data class ShowDeclineInviteMenu(val roomSummary: RoomListRoomSummary) : RoomListEvent
|
||||
data object HideDeclineInviteMenu : RoomListEvent
|
||||
|
||||
sealed interface ContextMenuEvents : RoomListEvents
|
||||
data object HideContextMenu : ContextMenuEvents
|
||||
data class LeaveRoom(val roomId: RoomId, val needsConfirmation: Boolean) : ContextMenuEvents
|
||||
data class MarkAsRead(val roomId: RoomId) : ContextMenuEvents
|
||||
data class MarkAsUnread(val roomId: RoomId) : ContextMenuEvents
|
||||
data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : ContextMenuEvents
|
||||
data class ClearCacheOfRoom(val roomId: RoomId) : ContextMenuEvents
|
||||
sealed interface ContextMenuEvent : RoomListEvent
|
||||
data object HideContextMenu : ContextMenuEvent
|
||||
data class LeaveRoom(val roomId: RoomId, val needsConfirmation: Boolean) : ContextMenuEvent
|
||||
data class MarkAsRead(val roomId: RoomId) : ContextMenuEvent
|
||||
data class MarkAsUnread(val roomId: RoomId) : ContextMenuEvent
|
||||
data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : ContextMenuEvent
|
||||
data class ClearCacheOfRoom(val roomId: RoomId) : ContextMenuEvent
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import io.element.android.features.announcement.api.Announcement
|
||||
import io.element.android.features.announcement.api.AnnouncementService
|
||||
import io.element.android.features.home.impl.datasource.RoomListDataSource
|
||||
import io.element.android.features.home.impl.filters.RoomListFiltersState
|
||||
import io.element.android.features.home.impl.search.RoomListSearchEvents
|
||||
import io.element.android.features.home.impl.search.RoomListSearchEvent
|
||||
import io.element.android.features.home.impl.search.RoomListSearchState
|
||||
import io.element.android.features.invite.api.SeenInvitesStore
|
||||
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents.AcceptInvite
|
||||
@@ -116,42 +116,42 @@ class RoomListPresenter(
|
||||
val contextMenu = remember { mutableStateOf<RoomListState.ContextMenu>(RoomListState.ContextMenu.Hidden) }
|
||||
val declineInviteMenu = remember { mutableStateOf<RoomListState.DeclineInviteMenu>(RoomListState.DeclineInviteMenu.Hidden) }
|
||||
|
||||
fun handleEvent(event: RoomListEvents) {
|
||||
fun handleEvent(event: RoomListEvent) {
|
||||
when (event) {
|
||||
is RoomListEvents.UpdateVisibleRange -> coroutineScope.launch {
|
||||
is RoomListEvent.UpdateVisibleRange -> coroutineScope.launch {
|
||||
updateVisibleRange(event.range)
|
||||
}
|
||||
RoomListEvents.DismissRequestVerificationPrompt -> securityBannerDismissed = true
|
||||
RoomListEvents.DismissBanner -> securityBannerDismissed = true
|
||||
RoomListEvents.DismissNewNotificationSoundBanner -> coroutineScope.launch {
|
||||
RoomListEvent.DismissRequestVerificationPrompt -> securityBannerDismissed = true
|
||||
RoomListEvent.DismissBanner -> securityBannerDismissed = true
|
||||
RoomListEvent.DismissNewNotificationSoundBanner -> coroutineScope.launch {
|
||||
announcementService.onAnnouncementDismissed(Announcement.NewNotificationSound)
|
||||
}
|
||||
RoomListEvents.ToggleSearchResults -> searchState.eventSink(RoomListSearchEvents.ToggleSearchVisibility)
|
||||
is RoomListEvents.ShowContextMenu -> {
|
||||
RoomListEvent.ToggleSearchResults -> searchState.eventSink(RoomListSearchEvent.ToggleSearchVisibility)
|
||||
is RoomListEvent.ShowContextMenu -> {
|
||||
coroutineScope.showContextMenu(event, contextMenu)
|
||||
}
|
||||
is RoomListEvents.HideContextMenu -> {
|
||||
is RoomListEvent.HideContextMenu -> {
|
||||
contextMenu.value = RoomListState.ContextMenu.Hidden
|
||||
}
|
||||
is RoomListEvents.LeaveRoom -> {
|
||||
is RoomListEvent.LeaveRoom -> {
|
||||
leaveRoomState.eventSink(LeaveRoomEvent.LeaveRoom(event.roomId, needsConfirmation = event.needsConfirmation))
|
||||
}
|
||||
is RoomListEvents.SetRoomIsFavorite -> coroutineScope.setRoomIsFavorite(event.roomId, event.isFavorite)
|
||||
is RoomListEvents.MarkAsRead -> coroutineScope.markAsRead(event.roomId)
|
||||
is RoomListEvents.MarkAsUnread -> coroutineScope.markAsUnread(event.roomId)
|
||||
is RoomListEvents.AcceptInvite -> {
|
||||
is RoomListEvent.SetRoomIsFavorite -> coroutineScope.setRoomIsFavorite(event.roomId, event.isFavorite)
|
||||
is RoomListEvent.MarkAsRead -> coroutineScope.markAsRead(event.roomId)
|
||||
is RoomListEvent.MarkAsUnread -> coroutineScope.markAsUnread(event.roomId)
|
||||
is RoomListEvent.AcceptInvite -> {
|
||||
acceptDeclineInviteState.eventSink(
|
||||
AcceptInvite(event.roomSummary.toInviteData())
|
||||
)
|
||||
}
|
||||
is RoomListEvents.DeclineInvite -> {
|
||||
is RoomListEvent.DeclineInvite -> {
|
||||
acceptDeclineInviteState.eventSink(
|
||||
DeclineInvite(event.roomSummary.toInviteData(), blockUser = event.blockUser, shouldConfirm = false)
|
||||
)
|
||||
}
|
||||
is RoomListEvents.ShowDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Shown(event.roomSummary)
|
||||
RoomListEvents.HideDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Hidden
|
||||
is RoomListEvents.ClearCacheOfRoom -> coroutineScope.clearCacheOfRoom(event.roomId)
|
||||
is RoomListEvent.ShowDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Shown(event.roomSummary)
|
||||
RoomListEvent.HideDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Hidden
|
||||
is RoomListEvent.ClearCacheOfRoom -> coroutineScope.clearCacheOfRoom(event.roomId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ class RoomListPresenter(
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun CoroutineScope.showContextMenu(event: RoomListEvents.ShowContextMenu, contextMenuState: MutableState<RoomListState.ContextMenu>) = launch {
|
||||
private fun CoroutineScope.showContextMenu(event: RoomListEvent.ShowContextMenu, contextMenuState: MutableState<RoomListState.ContextMenu>) = launch {
|
||||
val initialState = RoomListState.ContextMenu.Shown(
|
||||
roomId = event.roomSummary.roomId,
|
||||
roomName = event.roomSummary.name,
|
||||
|
||||
@@ -30,7 +30,7 @@ data class RoomListState(
|
||||
val acceptDeclineInviteState: AcceptDeclineInviteState,
|
||||
val hideInvitesAvatars: Boolean,
|
||||
val canReportRoom: Boolean,
|
||||
val eventSink: (RoomListEvents) -> Unit,
|
||||
val eventSink: (RoomListEvent) -> Unit,
|
||||
) {
|
||||
val displayFilters = contentState is RoomListContentState.Rooms
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ open class RoomListStateContextMenuShownProvider : PreviewParameterProvider<Room
|
||||
override val values: Sequence<RoomListState.ContextMenu.Shown>
|
||||
get() = sequenceOf(
|
||||
aContextMenuShown(hasNewContent = true),
|
||||
aContextMenuShown(isDm = true),
|
||||
aContextMenuShown(isDm = true, isFavorite = true),
|
||||
aContextMenuShown(roomName = null)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ internal fun aRoomListState(
|
||||
acceptDeclineInviteState: AcceptDeclineInviteState = anAcceptDeclineInviteState(),
|
||||
hideInvitesAvatars: Boolean = false,
|
||||
canReportRoom: Boolean = true,
|
||||
eventSink: (RoomListEvents) -> Unit = {}
|
||||
eventSink: (RoomListEvent) -> Unit = {}
|
||||
) = RoomListState(
|
||||
contextMenu = contextMenu,
|
||||
declineInviteMenu = declineInviteMenu,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
package io.element.android.features.home.impl.search
|
||||
|
||||
sealed interface RoomListSearchEvents {
|
||||
data object ToggleSearchVisibility : RoomListSearchEvents
|
||||
data object ClearQuery : RoomListSearchEvents
|
||||
sealed interface RoomListSearchEvent {
|
||||
data object ToggleSearchVisibility : RoomListSearchEvent
|
||||
data object ClearQuery : RoomListSearchEvent
|
||||
}
|
||||
@@ -45,12 +45,12 @@ class RoomListSearchPresenter(
|
||||
dataSource.setSearchQuery(searchQuery.text.toString())
|
||||
}
|
||||
|
||||
fun handleEvent(event: RoomListSearchEvents) {
|
||||
fun handleEvent(event: RoomListSearchEvent) {
|
||||
when (event) {
|
||||
RoomListSearchEvents.ClearQuery -> {
|
||||
RoomListSearchEvent.ClearQuery -> {
|
||||
searchQuery.clearText()
|
||||
}
|
||||
RoomListSearchEvents.ToggleSearchVisibility -> {
|
||||
RoomListSearchEvent.ToggleSearchVisibility -> {
|
||||
isSearchActive = !isSearchActive
|
||||
searchQuery.clearText()
|
||||
}
|
||||
|
||||
@@ -16,5 +16,5 @@ data class RoomListSearchState(
|
||||
val isSearchActive: Boolean,
|
||||
val query: TextFieldState,
|
||||
val results: ImmutableList<RoomListRoomSummary>,
|
||||
val eventSink: (RoomListSearchEvents) -> Unit
|
||||
val eventSink: (RoomListSearchEvent) -> Unit
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ fun aRoomListSearchState(
|
||||
isSearchActive: Boolean = false,
|
||||
query: String = "",
|
||||
results: ImmutableList<RoomListRoomSummary> = persistentListOf(),
|
||||
eventSink: (RoomListSearchEvents) -> Unit = { },
|
||||
eventSink: (RoomListSearchEvent) -> Unit = { },
|
||||
) = RoomListSearchState(
|
||||
isSearchActive = isSearchActive,
|
||||
query = TextFieldState(initialText = query),
|
||||
|
||||
@@ -38,7 +38,7 @@ import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.home.impl.components.RoomSummaryRow
|
||||
import io.element.android.features.home.impl.contentType
|
||||
import io.element.android.features.home.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvents
|
||||
import io.element.android.features.home.impl.roomlist.RoomListEvent
|
||||
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
|
||||
@@ -54,12 +54,12 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||
internal fun RoomListSearchView(
|
||||
state: RoomListSearchState,
|
||||
hideInvitesAvatars: Boolean,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
onRoomClick: (RoomId) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BackHandler(enabled = state.isSearchActive) {
|
||||
state.eventSink(RoomListSearchEvents.ToggleSearchVisibility)
|
||||
state.eventSink(RoomListSearchEvent.ToggleSearchVisibility)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
@@ -83,13 +83,13 @@ internal fun RoomListSearchView(
|
||||
private fun RoomListSearchContent(
|
||||
state: RoomListSearchState,
|
||||
hideInvitesAvatars: Boolean,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
onRoomClick: (RoomId) -> Unit,
|
||||
) {
|
||||
val borderColor = MaterialTheme.colorScheme.tertiary
|
||||
val strokeWidth = 1.dp
|
||||
fun onBackButtonClick() {
|
||||
state.eventSink(RoomListSearchEvents.ToggleSearchVisibility)
|
||||
state.eventSink(RoomListSearchEvent.ToggleSearchVisibility)
|
||||
}
|
||||
|
||||
fun onRoomClick(room: RoomListRoomSummary) {
|
||||
@@ -127,7 +127,7 @@ private fun RoomListSearchContent(
|
||||
),
|
||||
trailingIcon = if (state.query.text.isNotEmpty()) {
|
||||
@Composable {
|
||||
IconButton(onClick = { state.eventSink(RoomListSearchEvents.ClearQuery) }) {
|
||||
IconButton(onClick = { state.eventSink(RoomListSearchEvent.ClearQuery) }) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.Close(),
|
||||
contentDescription = stringResource(CommonStrings.action_cancel)
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package io.element.android.features.home.impl
|
||||
|
||||
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.announcement.api.Announcement
|
||||
import io.element.android.features.announcement.api.AnnouncementService
|
||||
@@ -70,9 +67,7 @@ class HomePresenterTest {
|
||||
),
|
||||
),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.currentUserAndNeighbors.first()).isEqualTo(
|
||||
MatrixUser(A_USER_ID, null, null)
|
||||
@@ -96,9 +91,7 @@ class HomePresenterTest {
|
||||
updateUserProfileResult = { _, _, _ -> },
|
||||
),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.canReportBug).isFalse()
|
||||
val finalState = awaitItem()
|
||||
@@ -115,9 +108,7 @@ class HomePresenterTest {
|
||||
updateUserProfileResult = { _, _, _ -> },
|
||||
),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showAvatarIndicator).isFalse()
|
||||
indicatorService.setShowRoomListTopBarIndicator(true)
|
||||
@@ -139,9 +130,7 @@ class HomePresenterTest {
|
||||
updateUserProfileResult = { _, _, _ -> },
|
||||
),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.currentUserAndNeighbors.first()).isEqualTo(MatrixUser(matrixClient.sessionId))
|
||||
// No new state is coming
|
||||
@@ -159,12 +148,10 @@ class HomePresenterTest {
|
||||
showAnnouncementResult = showAnnouncementResult,
|
||||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Chats)
|
||||
initialState.eventSink(HomeEvents.SelectHomeNavigationBarItem(HomeNavigationBarItem.Spaces))
|
||||
initialState.eventSink(HomeEvent.SelectHomeNavigationBarItem(HomeNavigationBarItem.Spaces))
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Spaces)
|
||||
showAnnouncementResult.assertions().isCalledOnce()
|
||||
@@ -189,7 +176,7 @@ class HomePresenterTest {
|
||||
assertThat(initialState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Chats)
|
||||
assertThat(initialState.showNavigationBar).isTrue()
|
||||
// User navigate to Spaces
|
||||
initialState.eventSink(HomeEvents.SelectHomeNavigationBarItem(HomeNavigationBarItem.Spaces))
|
||||
initialState.eventSink(HomeEvent.SelectHomeNavigationBarItem(HomeNavigationBarItem.Spaces))
|
||||
val spaceState = awaitItem()
|
||||
assertThat(spaceState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Spaces)
|
||||
// The last space is left
|
||||
|
||||
@@ -8,15 +8,13 @@
|
||||
|
||||
package io.element.android.features.home.impl.filters
|
||||
|
||||
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.home.impl.filters.selection.DefaultFilterSelectionStrategy
|
||||
import io.element.android.features.home.impl.filters.selection.FilterSelectionState
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
import io.element.android.tests.testutils.test
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter as MatrixRoomListFilter
|
||||
@@ -25,9 +23,7 @@ class RoomListFiltersPresenterTest {
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val presenter = createRoomListFiltersPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
awaitItem().let { state ->
|
||||
assertThat(state.hasAnyFilterSelected).isFalse()
|
||||
assertThat(state.filterSelectionStates).containsExactly(
|
||||
@@ -46,10 +42,8 @@ class RoomListFiltersPresenterTest {
|
||||
fun `present - toggle rooms filter`() = runTest {
|
||||
val roomListService = FakeRoomListService()
|
||||
val presenter = createRoomListFiltersPresenter(roomListService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms))
|
||||
presenter.test {
|
||||
awaitItem().eventSink.invoke(RoomListFiltersEvent.ToggleFilter(RoomListFilter.Rooms))
|
||||
awaitLastSequentialItem().let { state ->
|
||||
|
||||
assertThat(state.hasAnyFilterSelected).isTrue()
|
||||
@@ -66,7 +60,7 @@ class RoomListFiltersPresenterTest {
|
||||
assertThat(roomListCurrentFilter.filters).containsExactly(
|
||||
MatrixRoomListFilter.Category.Group,
|
||||
)
|
||||
state.eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms))
|
||||
state.eventSink.invoke(RoomListFiltersEvent.ToggleFilter(RoomListFilter.Rooms))
|
||||
}
|
||||
awaitLastSequentialItem().let { state ->
|
||||
assertThat(state.hasAnyFilterSelected).isFalse()
|
||||
@@ -88,13 +82,11 @@ class RoomListFiltersPresenterTest {
|
||||
fun `present - clear filters event`() = runTest {
|
||||
val roomListService = FakeRoomListService()
|
||||
val presenter = createRoomListFiltersPresenter(roomListService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms))
|
||||
presenter.test {
|
||||
awaitItem().eventSink.invoke(RoomListFiltersEvent.ToggleFilter(RoomListFilter.Rooms))
|
||||
awaitLastSequentialItem().let { state ->
|
||||
assertThat(state.hasAnyFilterSelected).isTrue()
|
||||
state.eventSink.invoke(RoomListFiltersEvents.ClearSelectedFilters)
|
||||
state.eventSink.invoke(RoomListFiltersEvent.ClearSelectedFilters)
|
||||
}
|
||||
awaitLastSequentialItem().let { state ->
|
||||
assertThat(state.hasAnyFilterSelected).isFalse()
|
||||
|
||||
@@ -27,7 +27,7 @@ class RoomListFiltersViewTest {
|
||||
|
||||
@Test
|
||||
fun `clicking on filters generates expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListFiltersEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListFiltersEvent>()
|
||||
rule.setContent {
|
||||
RoomListFiltersView(
|
||||
state = aRoomListFiltersState(eventSink = eventsRecorder),
|
||||
@@ -36,14 +36,14 @@ class RoomListFiltersViewTest {
|
||||
rule.clickOn(R.string.screen_roomlist_filter_rooms)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms),
|
||||
RoomListFiltersEvent.ToggleFilter(RoomListFilter.Rooms),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on clear filters generates expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListFiltersEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListFiltersEvent>()
|
||||
rule.setContent {
|
||||
RoomListFiltersView(
|
||||
state = aRoomListFiltersState(
|
||||
@@ -55,7 +55,7 @@ class RoomListFiltersViewTest {
|
||||
rule.pressTag(TestTags.homeScreenClearFilters.value)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListFiltersEvents.ClearSelectedFilters,
|
||||
RoomListFiltersEvent.ClearSelectedFilters,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class RoomListContextMenuTest {
|
||||
|
||||
@Test
|
||||
fun `clicking on Mark as read generates expected Events`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val contextMenu = aContextMenuShown(hasNewContent = true)
|
||||
rule.setRoomListContextMenu(
|
||||
contextMenu = contextMenu,
|
||||
@@ -39,15 +39,15 @@ class RoomListContextMenuTest {
|
||||
rule.clickOn(R.string.screen_roomlist_mark_as_read)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListEvents.HideContextMenu,
|
||||
RoomListEvents.MarkAsRead(contextMenu.roomId),
|
||||
RoomListEvent.HideContextMenu,
|
||||
RoomListEvent.MarkAsRead(contextMenu.roomId),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on Mark as unread generates expected Events`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val contextMenu = aContextMenuShown(hasNewContent = false)
|
||||
rule.setRoomListContextMenu(
|
||||
contextMenu = contextMenu,
|
||||
@@ -56,15 +56,15 @@ class RoomListContextMenuTest {
|
||||
rule.clickOn(R.string.screen_roomlist_mark_as_unread)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListEvents.HideContextMenu,
|
||||
RoomListEvents.MarkAsUnread(contextMenu.roomId),
|
||||
RoomListEvent.HideContextMenu,
|
||||
RoomListEvent.MarkAsUnread(contextMenu.roomId),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on Leave room generates expected Events`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val contextMenu = aContextMenuShown(isDm = false)
|
||||
rule.setRoomListContextMenu(
|
||||
contextMenu = contextMenu,
|
||||
@@ -73,15 +73,15 @@ class RoomListContextMenuTest {
|
||||
rule.clickOn(CommonStrings.action_leave_room)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListEvents.HideContextMenu,
|
||||
RoomListEvents.LeaveRoom(contextMenu.roomId, needsConfirmation = true),
|
||||
RoomListEvent.HideContextMenu,
|
||||
RoomListEvent.LeaveRoom(contextMenu.roomId, needsConfirmation = true),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on Report room invokes the expected callback and generates expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val contextMenu = aContextMenuShown()
|
||||
val callback = EnsureCalledOnceWithParam(contextMenu.roomId, Unit)
|
||||
rule.setRoomListContextMenu(
|
||||
@@ -92,13 +92,13 @@ class RoomListContextMenuTest {
|
||||
onReportRoomClick = callback,
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_report_room)
|
||||
eventsRecorder.assertSingle(RoomListEvents.HideContextMenu)
|
||||
eventsRecorder.assertSingle(RoomListEvent.HideContextMenu)
|
||||
callback.assertSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on Settings invokes the expected callback and generates expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val contextMenu = aContextMenuShown()
|
||||
val callback = EnsureCalledOnceWithParam(contextMenu.roomId, Unit)
|
||||
rule.setRoomListContextMenu(
|
||||
@@ -107,13 +107,13 @@ class RoomListContextMenuTest {
|
||||
onRoomSettingsClick = callback,
|
||||
)
|
||||
rule.clickOn(CommonStrings.common_settings)
|
||||
eventsRecorder.assertSingle(RoomListEvents.HideContextMenu)
|
||||
eventsRecorder.assertSingle(RoomListEvent.HideContextMenu)
|
||||
callback.assertSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on Favourites generates expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val contextMenu = aContextMenuShown(isDm = false, isFavorite = false)
|
||||
val callback = EnsureNeverCalledWithParam<RoomId>()
|
||||
rule.setRoomListContextMenu(
|
||||
@@ -124,7 +124,7 @@ class RoomListContextMenuTest {
|
||||
rule.clickOn(CommonStrings.common_favourite)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListEvents.SetRoomIsFavorite(contextMenu.roomId, true),
|
||||
RoomListEvent.SetRoomIsFavorite(contextMenu.roomId, true),
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -132,7 +132,7 @@ class RoomListContextMenuTest {
|
||||
private fun AndroidComposeTestRule<*, *>.setRoomListContextMenu(
|
||||
contextMenu: RoomListState.ContextMenu.Shown,
|
||||
canReportRoom: Boolean = false,
|
||||
eventSink: (RoomListEvents) -> Unit,
|
||||
eventSink: (RoomListEvent) -> Unit,
|
||||
onRoomSettingsClick: (RoomId) -> Unit = EnsureNeverCalledWithParam(),
|
||||
onReportRoomClick: (RoomId) -> Unit = EnsureNeverCalledWithParam(),
|
||||
) {
|
||||
|
||||
@@ -28,7 +28,7 @@ class RoomListDeclineInviteMenuTest {
|
||||
|
||||
@Test
|
||||
fun `clicking on decline emits the expected Events`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val menu = RoomListState.DeclineInviteMenu.Shown(roomSummary = aRoomListRoomSummary())
|
||||
rule.setSafeContent {
|
||||
RoomListDeclineInviteMenu(
|
||||
@@ -41,15 +41,15 @@ class RoomListDeclineInviteMenuTest {
|
||||
rule.clickOn(CommonStrings.action_decline)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListEvents.HideDeclineInviteMenu,
|
||||
RoomListEvents.DeclineInvite(menu.roomSummary, blockUser = false),
|
||||
RoomListEvent.HideDeclineInviteMenu,
|
||||
RoomListEvent.DeclineInvite(menu.roomSummary, blockUser = false),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on decline and block when canReportRoom=true, it emits the expected Events and callback`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val menu = RoomListState.DeclineInviteMenu.Shown(roomSummary = aRoomListRoomSummary())
|
||||
rule.setSafeContent {
|
||||
RoomListDeclineInviteMenu(
|
||||
@@ -60,13 +60,13 @@ class RoomListDeclineInviteMenuTest {
|
||||
)
|
||||
}
|
||||
rule.clickOn(CommonStrings.action_decline_and_block)
|
||||
val expectedEvents = listOf(RoomListEvents.HideDeclineInviteMenu)
|
||||
val expectedEvents = listOf(RoomListEvent.HideDeclineInviteMenu)
|
||||
eventsRecorder.assertList(expectedEvents)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on decline and block when canReportRoom=false, it emits the expected Events`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val menu = RoomListState.DeclineInviteMenu.Shown(roomSummary = aRoomListRoomSummary())
|
||||
rule.setSafeContent {
|
||||
RoomListDeclineInviteMenu(
|
||||
@@ -78,15 +78,15 @@ class RoomListDeclineInviteMenuTest {
|
||||
}
|
||||
rule.clickOn(CommonStrings.action_decline_and_block)
|
||||
val expectedEvents = listOf(
|
||||
RoomListEvents.HideDeclineInviteMenu,
|
||||
RoomListEvents.DeclineInvite(menu.roomSummary, blockUser = true),
|
||||
RoomListEvent.HideDeclineInviteMenu,
|
||||
RoomListEvent.DeclineInvite(menu.roomSummary, blockUser = true),
|
||||
)
|
||||
eventsRecorder.assertList(expectedEvents)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on cancel emits the expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val menu = RoomListState.DeclineInviteMenu.Shown(roomSummary = aRoomListRoomSummary())
|
||||
rule.setSafeContent {
|
||||
RoomListDeclineInviteMenu(
|
||||
@@ -97,6 +97,6 @@ class RoomListDeclineInviteMenuTest {
|
||||
)
|
||||
}
|
||||
rule.clickOn(CommonStrings.action_cancel)
|
||||
eventsRecorder.assertList(listOf(RoomListEvents.HideDeclineInviteMenu))
|
||||
eventsRecorder.assertList(listOf(RoomListEvent.HideDeclineInviteMenu))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package io.element.android.features.home.impl.roomlist
|
||||
|
||||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import io.element.android.features.announcement.api.Announcement
|
||||
@@ -21,7 +18,7 @@ import io.element.android.features.home.impl.datasource.aRoomListRoomSummaryFact
|
||||
import io.element.android.features.home.impl.filters.RoomListFiltersState
|
||||
import io.element.android.features.home.impl.filters.aRoomListFiltersState
|
||||
import io.element.android.features.home.impl.model.createRoomListRoomSummary
|
||||
import io.element.android.features.home.impl.search.RoomListSearchEvents
|
||||
import io.element.android.features.home.impl.search.RoomListSearchEvent
|
||||
import io.element.android.features.home.impl.search.RoomListSearchState
|
||||
import io.element.android.features.home.impl.search.aRoomListSearchState
|
||||
import io.element.android.features.invite.api.SeenInvitesStore
|
||||
@@ -141,15 +138,13 @@ class RoomListPresenterTest {
|
||||
val presenter = createRoomListPresenter(
|
||||
client = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService, syncService = syncService),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val eventWithContentAsRooms = consumeItemsUntilPredicate {
|
||||
it.contentState is RoomListContentState.Rooms
|
||||
}.last()
|
||||
val eventSink = eventWithContentAsRooms.eventSink
|
||||
assertThat(eventWithContentAsRooms.contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.RecoveryKeyConfirmation)
|
||||
eventSink(RoomListEvents.DismissRequestVerificationPrompt)
|
||||
eventSink(RoomListEvent.DismissRequestVerificationPrompt)
|
||||
assertThat(awaitItem().contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.None)
|
||||
}
|
||||
}
|
||||
@@ -173,9 +168,7 @@ class RoomListPresenterTest {
|
||||
val presenter = createRoomListPresenter(
|
||||
client = matrixClient,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = consumeItemsUntilPredicate {
|
||||
it.contentState is RoomListContentState.Rooms
|
||||
}.last()
|
||||
@@ -194,7 +187,7 @@ class RoomListPresenterTest {
|
||||
assertThat(awaitItem().contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.None)
|
||||
encryptionService.emitRecoveryState(RecoveryState.DISABLED)
|
||||
assertThat(awaitItem().contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.SetUpRecovery)
|
||||
nextState.eventSink(RoomListEvents.DismissBanner)
|
||||
nextState.eventSink(RoomListEvent.DismissBanner)
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.None)
|
||||
}
|
||||
@@ -207,12 +200,10 @@ class RoomListPresenterTest {
|
||||
givenGetRoomResult(A_ROOM_ID, room)
|
||||
}
|
||||
val presenter = createRoomListPresenter(client = client)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val summary = createRoomListRoomSummary()
|
||||
initialState.eventSink(RoomListEvents.ShowContextMenu(summary))
|
||||
initialState.eventSink(RoomListEvent.ShowContextMenu(summary))
|
||||
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.contextMenu)
|
||||
@@ -257,7 +248,7 @@ class RoomListPresenterTest {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val summary = createRoomListRoomSummary()
|
||||
initialState.eventSink(RoomListEvents.ShowContextMenu(summary))
|
||||
initialState.eventSink(RoomListEvent.ShowContextMenu(summary))
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.contextMenu)
|
||||
.isEqualTo(
|
||||
@@ -282,12 +273,10 @@ class RoomListPresenterTest {
|
||||
givenGetRoomResult(A_ROOM_ID, room)
|
||||
}
|
||||
val presenter = createRoomListPresenter(client = client)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val summary = createRoomListRoomSummary()
|
||||
initialState.eventSink(RoomListEvents.ShowContextMenu(summary))
|
||||
initialState.eventSink(RoomListEvent.ShowContextMenu(summary))
|
||||
|
||||
val shownState = awaitItem()
|
||||
assertThat(shownState.contextMenu)
|
||||
@@ -302,7 +291,7 @@ class RoomListPresenterTest {
|
||||
)
|
||||
)
|
||||
|
||||
shownState.eventSink(RoomListEvents.HideContextMenu)
|
||||
shownState.eventSink(RoomListEvent.HideContextMenu)
|
||||
|
||||
val hiddenState = awaitItem()
|
||||
assertThat(hiddenState.contextMenu).isEqualTo(RoomListState.ContextMenu.Hidden)
|
||||
@@ -315,11 +304,9 @@ class RoomListPresenterTest {
|
||||
val presenter = createRoomListPresenter(
|
||||
leaveRoomState = aLeaveRoomState(eventSink = leaveRoomEventsRecorder),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomListEvents.LeaveRoom(A_ROOM_ID, needsConfirmation = true))
|
||||
initialState.eventSink(RoomListEvent.LeaveRoom(A_ROOM_ID, needsConfirmation = true))
|
||||
leaveRoomEventsRecorder.assertSingle(LeaveRoomEvent.LeaveRoom(A_ROOM_ID, needsConfirmation = true))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
@@ -327,7 +314,7 @@ class RoomListPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - toggle search menu`() = runTest {
|
||||
val eventRecorder = EventsRecorder<RoomListSearchEvents>()
|
||||
val eventRecorder = EventsRecorder<RoomListSearchEvent>()
|
||||
val searchPresenter: Presenter<RoomListSearchState> = Presenter {
|
||||
aRoomListSearchState(
|
||||
eventSink = eventRecorder
|
||||
@@ -336,20 +323,18 @@ class RoomListPresenterTest {
|
||||
val presenter = createRoomListPresenter(
|
||||
searchPresenter = searchPresenter,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
eventRecorder.assertEmpty()
|
||||
initialState.eventSink(RoomListEvents.ToggleSearchResults)
|
||||
initialState.eventSink(RoomListEvent.ToggleSearchResults)
|
||||
eventRecorder.assertSingle(
|
||||
RoomListSearchEvents.ToggleSearchVisibility
|
||||
RoomListSearchEvent.ToggleSearchVisibility
|
||||
)
|
||||
initialState.eventSink(RoomListEvents.ToggleSearchResults)
|
||||
initialState.eventSink(RoomListEvent.ToggleSearchResults)
|
||||
eventRecorder.assertList(
|
||||
listOf(
|
||||
RoomListSearchEvents.ToggleSearchVisibility,
|
||||
RoomListSearchEvents.ToggleSearchVisibility
|
||||
RoomListSearchEvent.ToggleSearchVisibility,
|
||||
RoomListSearchEvent.ToggleSearchVisibility
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -367,9 +352,7 @@ class RoomListPresenterTest {
|
||||
notificationSettingsService = notificationSettingsService
|
||||
)
|
||||
val presenter = createRoomListPresenter(client = matrixClient)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
notificationSettingsService.setRoomNotificationMode(A_ROOM_ID, userDefinedMode)
|
||||
val updatedState = consumeItemsUntilPredicate { state ->
|
||||
(state.contentState as? RoomListContentState.Rooms)?.summaries.orEmpty().any { summary ->
|
||||
@@ -394,13 +377,11 @@ class RoomListPresenterTest {
|
||||
givenGetRoomResult(A_ROOM_ID, room)
|
||||
}
|
||||
val presenter = createRoomListPresenter(client = client, analyticsService = analyticsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomListEvents.SetRoomIsFavorite(A_ROOM_ID, true))
|
||||
initialState.eventSink(RoomListEvent.SetRoomIsFavorite(A_ROOM_ID, true))
|
||||
setIsFavoriteResult.assertions().isCalledOnce().with(value(true))
|
||||
initialState.eventSink(RoomListEvents.SetRoomIsFavorite(A_ROOM_ID, false))
|
||||
initialState.eventSink(RoomListEvent.SetRoomIsFavorite(A_ROOM_ID, false))
|
||||
setIsFavoriteResult.assertions().isCalledExactly(2)
|
||||
.withSequence(
|
||||
listOf(value(true)),
|
||||
@@ -424,9 +405,7 @@ class RoomListPresenterTest {
|
||||
val presenter = createRoomListPresenter(
|
||||
client = matrixClient,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
assertThat(awaitItem().contentState).isInstanceOf(RoomListContentState.Empty::class.java)
|
||||
}
|
||||
}
|
||||
@@ -463,23 +442,21 @@ class RoomListPresenterTest {
|
||||
analyticsService = analyticsService,
|
||||
notificationCleaner = notificationCleaner,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
allRooms.forEach {
|
||||
assertThat(it.setUnreadFlagCalls).isEmpty()
|
||||
}
|
||||
initialState.eventSink.invoke(RoomListEvents.MarkAsRead(A_ROOM_ID))
|
||||
initialState.eventSink.invoke(RoomListEvent.MarkAsRead(A_ROOM_ID))
|
||||
markAsReadResult.assertions().isCalledOnce().with(value(ReceiptType.READ))
|
||||
assertThat(room.setUnreadFlagCalls).isEqualTo(listOf(false))
|
||||
clearMessagesForRoomLambda.assertions().isCalledOnce()
|
||||
.with(value(A_SESSION_ID), value(A_ROOM_ID))
|
||||
initialState.eventSink.invoke(RoomListEvents.MarkAsUnread(A_ROOM_ID_2))
|
||||
initialState.eventSink.invoke(RoomListEvent.MarkAsUnread(A_ROOM_ID_2))
|
||||
assertThat(room2.setUnreadFlagCalls).isEqualTo(listOf(true))
|
||||
// Test again with private read receipts
|
||||
sessionPreferencesStore.setSendPublicReadReceipts(false)
|
||||
initialState.eventSink.invoke(RoomListEvents.MarkAsRead(A_ROOM_ID_3))
|
||||
initialState.eventSink.invoke(RoomListEvent.MarkAsRead(A_ROOM_ID_3))
|
||||
markAsReadResult3.assertions().isCalledOnce().with(value(ReceiptType.READ_PRIVATE))
|
||||
assertThat(room3.setUnreadFlagCalls).isEqualTo(listOf(false))
|
||||
clearMessagesForRoomLambda.assertions().isCalledExactly(2)
|
||||
@@ -525,8 +502,8 @@ class RoomListPresenterTest {
|
||||
it.id == roomSummary.roomId.value
|
||||
}
|
||||
|
||||
state.eventSink(RoomListEvents.AcceptInvite(roomListRoomSummary))
|
||||
state.eventSink(RoomListEvents.DeclineInvite(roomListRoomSummary, blockUser = false))
|
||||
state.eventSink(RoomListEvent.AcceptInvite(roomListRoomSummary))
|
||||
state.eventSink(RoomListEvent.DeclineInvite(roomListRoomSummary, blockUser = false))
|
||||
|
||||
val inviteData = roomListRoomSummary.toInviteData()
|
||||
assert(eventSinkRecorder)
|
||||
@@ -559,9 +536,9 @@ class RoomListPresenterTest {
|
||||
it.contentState is RoomListContentState.Rooms
|
||||
}.last()
|
||||
|
||||
state.eventSink(RoomListEvents.UpdateVisibleRange(IntRange(0, 10)))
|
||||
state.eventSink(RoomListEvent.UpdateVisibleRange(IntRange(0, 10)))
|
||||
// If called again, it will cancel the current one, which should not result in a test failure
|
||||
state.eventSink(RoomListEvents.UpdateVisibleRange(IntRange(0, 11)))
|
||||
state.eventSink(RoomListEvent.UpdateVisibleRange(IntRange(0, 11)))
|
||||
advanceTimeBy(1.seconds)
|
||||
subscribeToVisibleRoomsLambda.assertions().isCalledOnce()
|
||||
}
|
||||
@@ -588,12 +565,12 @@ class RoomListPresenterTest {
|
||||
it.contentState is RoomListContentState.Rooms
|
||||
}.last()
|
||||
|
||||
state.eventSink(RoomListEvents.UpdateVisibleRange(IntRange(0, 10)))
|
||||
state.eventSink(RoomListEvent.UpdateVisibleRange(IntRange(0, 10)))
|
||||
advanceTimeBy(1.seconds)
|
||||
subscribeToVisibleRoomsLambda.assertions().isCalledOnce()
|
||||
|
||||
// If called again, it will subscribe to the next items
|
||||
state.eventSink(RoomListEvents.UpdateVisibleRange(IntRange(0, 11)))
|
||||
state.eventSink(RoomListEvent.UpdateVisibleRange(IntRange(0, 11)))
|
||||
advanceTimeBy(1.seconds)
|
||||
subscribeToVisibleRoomsLambda.assertions().isCalledExactly(2)
|
||||
}
|
||||
@@ -626,7 +603,7 @@ class RoomListPresenterTest {
|
||||
assertThat(state.contentAsRooms().showNewNotificationSoundBanner).isFalse()
|
||||
announcementService.emitAnnouncementsToShow(listOf(Announcement.NewNotificationSound))
|
||||
assertThat(awaitItem().contentAsRooms().showNewNotificationSoundBanner).isTrue()
|
||||
state.eventSink(RoomListEvents.DismissNewNotificationSoundBanner)
|
||||
state.eventSink(RoomListEvent.DismissNewNotificationSoundBanner)
|
||||
onAnnouncementDismissedResult.assertions().isCalledOnce()
|
||||
.with(value(Announcement.NewNotificationSound))
|
||||
// Simulate service updating the value
|
||||
|
||||
@@ -46,7 +46,7 @@ class RoomListViewTest {
|
||||
@Config(qualifiers = "h1024dp")
|
||||
@Test
|
||||
fun `displaying the view automatically sends a couple of UpdateVisibleRangeEvents`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
rule.setRoomListView(
|
||||
state = aRoomListState(
|
||||
contentState = aRoomsContentState(securityBannerState = SecurityBannerState.RecoveryKeyConfirmation),
|
||||
@@ -56,15 +56,15 @@ class RoomListViewTest {
|
||||
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListEvents.UpdateVisibleRange(IntRange.EMPTY),
|
||||
RoomListEvents.UpdateVisibleRange(0..5),
|
||||
RoomListEvent.UpdateVisibleRange(IntRange.EMPTY),
|
||||
RoomListEvent.UpdateVisibleRange(0..5),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on close recovery key banner emits the expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
rule.setRoomListView(
|
||||
state = aRoomListState(
|
||||
contentState = aRoomsContentState(securityBannerState = SecurityBannerState.RecoveryKeyConfirmation),
|
||||
@@ -77,12 +77,12 @@ class RoomListViewTest {
|
||||
|
||||
val close = rule.activity.getString(CommonStrings.action_close)
|
||||
rule.onNodeWithContentDescription(close).performClick()
|
||||
eventsRecorder.assertSingle(RoomListEvents.DismissBanner)
|
||||
eventsRecorder.assertSingle(RoomListEvent.DismissBanner)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on close setup key banner emits the expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
rule.setRoomListView(
|
||||
state = aRoomListState(
|
||||
contentState = aRoomsContentState(securityBannerState = SecurityBannerState.SetUpRecovery),
|
||||
@@ -95,12 +95,12 @@ class RoomListViewTest {
|
||||
|
||||
val close = rule.activity.getString(CommonStrings.action_close)
|
||||
rule.onNodeWithContentDescription(close).performClick()
|
||||
eventsRecorder.assertSingle(RoomListEvents.DismissBanner)
|
||||
eventsRecorder.assertSingle(RoomListEvent.DismissBanner)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on continue recovery key banner invokes the expected callback`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setRoomListView(
|
||||
state = aRoomListState(
|
||||
@@ -121,7 +121,7 @@ class RoomListViewTest {
|
||||
|
||||
@Test
|
||||
fun `clicking on continue setup key banner invokes the expected callback`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setRoomListView(
|
||||
state = aRoomListState(
|
||||
@@ -139,7 +139,7 @@ class RoomListViewTest {
|
||||
|
||||
@Test
|
||||
fun `clicking on start chat when the session has no room invokes the expected callback`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>(expectEvents = false)
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>(expectEvents = false)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setRoomListView(
|
||||
state = aRoomListState(
|
||||
@@ -154,7 +154,7 @@ class RoomListViewTest {
|
||||
|
||||
@Test
|
||||
fun `clicking on a room invokes the expected callback`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val state = aRoomListState(
|
||||
eventSink = eventsRecorder,
|
||||
)
|
||||
@@ -178,7 +178,7 @@ class RoomListViewTest {
|
||||
|
||||
@Test
|
||||
fun `clicking on a room twice invokes the expected callback only once`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val state = aRoomListState(
|
||||
eventSink = eventsRecorder,
|
||||
)
|
||||
@@ -201,7 +201,7 @@ class RoomListViewTest {
|
||||
|
||||
@Test
|
||||
fun `long clicking on a room emits the expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val state = aRoomListState(
|
||||
eventSink = eventsRecorder,
|
||||
)
|
||||
@@ -215,12 +215,12 @@ class RoomListViewTest {
|
||||
eventsRecorder.clear()
|
||||
|
||||
rule.onNodeWithText(room0.latestEvent.content().toString()).performTouchInput { longClick() }
|
||||
eventsRecorder.assertSingle(RoomListEvents.ShowContextMenu(room0))
|
||||
eventsRecorder.assertSingle(RoomListEvent.ShowContextMenu(room0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on a room setting invokes the expected callback and emits expected Event`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val state = aRoomListState(
|
||||
contextMenu = aContextMenuShown(),
|
||||
eventSink = eventsRecorder,
|
||||
@@ -238,12 +238,12 @@ class RoomListViewTest {
|
||||
rule.clickOn(CommonStrings.common_settings)
|
||||
}
|
||||
|
||||
eventsRecorder.assertSingle(RoomListEvents.HideContextMenu)
|
||||
eventsRecorder.assertSingle(RoomListEvent.HideContextMenu)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on accept and decline invite emits the expected Events`() {
|
||||
val eventsRecorder = EventsRecorder<RoomListEvents>()
|
||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||
val state = aRoomListState(
|
||||
eventSink = eventsRecorder,
|
||||
)
|
||||
@@ -259,8 +259,8 @@ class RoomListViewTest {
|
||||
rule.clickOn(CommonStrings.action_decline)
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
RoomListEvents.AcceptInvite(invitedRoom),
|
||||
RoomListEvents.ShowDeclineInviteMenu(invitedRoom),
|
||||
RoomListEvent.AcceptInvite(invitedRoom),
|
||||
RoomListEvent.ShowDeclineInviteMenu(invitedRoom),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package io.element.android.features.home.impl.search
|
||||
|
||||
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.home.impl.datasource.aRoomListRoomSummaryFactory
|
||||
import io.element.android.libraries.dateformatter.test.FakeDateFormatter
|
||||
@@ -19,6 +16,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.tests.testutils.test
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
@@ -29,9 +27,7 @@ class RoomListSearchPresenterTest {
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val presenter = createRoomListSearchPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
awaitItem().let { state ->
|
||||
assertThat(state.isSearchActive).isFalse()
|
||||
assertThat(state.query.text.toString()).isEmpty()
|
||||
@@ -43,16 +39,14 @@ class RoomListSearchPresenterTest {
|
||||
@Test
|
||||
fun `present - toggle search visibility`() = runTest {
|
||||
val presenter = createRoomListSearchPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
awaitItem().let { state ->
|
||||
assertThat(state.isSearchActive).isFalse()
|
||||
state.eventSink(RoomListSearchEvents.ToggleSearchVisibility)
|
||||
state.eventSink(RoomListSearchEvent.ToggleSearchVisibility)
|
||||
}
|
||||
awaitItem().let { state ->
|
||||
assertThat(state.isSearchActive).isTrue()
|
||||
state.eventSink(RoomListSearchEvents.ToggleSearchVisibility)
|
||||
state.eventSink(RoomListSearchEvent.ToggleSearchVisibility)
|
||||
}
|
||||
awaitItem().let { state ->
|
||||
assertThat(state.isSearchActive).isFalse()
|
||||
@@ -64,9 +58,7 @@ class RoomListSearchPresenterTest {
|
||||
fun `present - query search changes`() = runTest {
|
||||
val roomListService = FakeRoomListService()
|
||||
val presenter = createRoomListSearchPresenter(roomListService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
awaitItem().let { state ->
|
||||
assertThat(
|
||||
roomListService.allRooms.currentFilter.value
|
||||
@@ -82,7 +74,7 @@ class RoomListSearchPresenterTest {
|
||||
).isEqualTo(
|
||||
RoomListFilter.NormalizedMatchRoomName("Search")
|
||||
)
|
||||
state.eventSink(RoomListSearchEvents.ClearQuery)
|
||||
state.eventSink(RoomListSearchEvent.ClearQuery)
|
||||
}
|
||||
awaitItem().let { state ->
|
||||
assertThat(state.query.text.toString()).isEmpty()
|
||||
@@ -99,9 +91,7 @@ class RoomListSearchPresenterTest {
|
||||
fun `present - room list changes`() = runTest {
|
||||
val roomListService = FakeRoomListService()
|
||||
val presenter = createRoomListSearchPresenter(roomListService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
awaitItem().let { state ->
|
||||
assertThat(state.results).isEmpty()
|
||||
}
|
||||
|
||||
@@ -589,9 +589,14 @@ private fun FavoriteItem(
|
||||
isFavorite: Boolean,
|
||||
onFavoriteChanges: (Boolean) -> Unit,
|
||||
) {
|
||||
val (textResId, icon) = if (isFavorite) {
|
||||
CommonStrings.common_favourited to CompoundIcons.FavouriteSolid()
|
||||
} else {
|
||||
CommonStrings.common_favourite to CompoundIcons.Favourite()
|
||||
}
|
||||
PreferenceSwitch(
|
||||
icon = CompoundIcons.Favourite(),
|
||||
title = stringResource(id = CommonStrings.common_favourite),
|
||||
icon = icon,
|
||||
title = stringResource(id = textResId),
|
||||
isChecked = isFavorite,
|
||||
onCheckedChange = onFavoriteChanges
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ package io.element.android.features.roomdetails.impl.members
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
|
||||
sealed interface RoomMemberListEvents {
|
||||
data class ChangeSelectedSection(val section: SelectedSection) : RoomMemberListEvents
|
||||
data class RoomMemberSelected(val roomMember: RoomMember) : RoomMemberListEvents
|
||||
sealed interface RoomMemberListEvent {
|
||||
data class ChangeSelectedSection(val section: SelectedSection) : RoomMemberListEvent
|
||||
data class RoomMemberSelected(val roomMember: RoomMember) : RoomMemberListEvent
|
||||
}
|
||||
@@ -125,11 +125,11 @@ class RoomMemberListPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvent(event: RoomMemberListEvents) {
|
||||
fun handleEvent(event: RoomMemberListEvent) {
|
||||
when (event) {
|
||||
is RoomMemberListEvents.RoomMemberSelected ->
|
||||
is RoomMemberListEvent.RoomMemberSelected ->
|
||||
roomModerationState.eventSink(ShowActionsForUser(event.roomMember.toMatrixUser()))
|
||||
is RoomMemberListEvents.ChangeSelectedSection -> selectedSection = event.section
|
||||
is RoomMemberListEvent.ChangeSelectedSection -> selectedSection = event.section
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ data class RoomMemberListState(
|
||||
val canInvite: Boolean,
|
||||
val selectedSection: SelectedSection,
|
||||
val moderationState: RoomMemberModerationState,
|
||||
val eventSink: (RoomMemberListEvents) -> Unit,
|
||||
val eventSink: (RoomMemberListEvent) -> Unit,
|
||||
) {
|
||||
val showBannedSection: Boolean = moderationState.permissions.canBan && roomMembers.dataOrNull()?.banned?.isNotEmpty() == true
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ internal fun aRoomMemberListState(
|
||||
selectedSection: SelectedSection = SelectedSection.MEMBERS,
|
||||
searchQuery: String = "",
|
||||
canInvite: Boolean = false,
|
||||
eventSink: (RoomMemberListEvents) -> Unit = {},
|
||||
eventSink: (RoomMemberListEvent) -> Unit = {},
|
||||
) = RoomMemberListState(
|
||||
roomMembers = roomMembers,
|
||||
filteredRoomMembers = roomMembers.map { it.filter(searchQuery) },
|
||||
|
||||
@@ -25,8 +25,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
@@ -68,7 +66,7 @@ fun RoomMemberListView(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
fun onSelectUser(roomMember: RoomMember) {
|
||||
state.eventSink(RoomMemberListEvents.RoomMemberSelected(roomMember))
|
||||
state.eventSink(RoomMemberListEvent.RoomMemberSelected(roomMember))
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
@@ -100,7 +98,7 @@ fun RoomMemberListView(
|
||||
selectedSection = state.selectedSection,
|
||||
showBannedSection = state.showBannedSection,
|
||||
searchQuery = state.searchQuery.text.toString(),
|
||||
onSelectedSectionChange = { state.eventSink(RoomMemberListEvents.ChangeSelectedSection(it)) },
|
||||
onSelectedSectionChange = { state.eventSink(RoomMemberListEvent.ChangeSelectedSection(it)) },
|
||||
onSelectUser = ::onSelectUser,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ package io.element.android.features.roomdetails.impl.notificationsettings
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
|
||||
sealed interface RoomNotificationSettingsEvents {
|
||||
data class ChangeRoomNotificationMode(val mode: RoomNotificationMode) : RoomNotificationSettingsEvents
|
||||
data class SetNotificationMode(val isDefault: Boolean) : RoomNotificationSettingsEvents
|
||||
data object DeleteCustomNotification : RoomNotificationSettingsEvents
|
||||
data object ClearSetNotificationError : RoomNotificationSettingsEvents
|
||||
data object ClearRestoreDefaultError : RoomNotificationSettingsEvents
|
||||
sealed interface RoomNotificationSettingsEvent {
|
||||
data class ChangeRoomNotificationMode(val mode: RoomNotificationMode) : RoomNotificationSettingsEvent
|
||||
data class SetNotificationMode(val isDefault: Boolean) : RoomNotificationSettingsEvent
|
||||
data object DeleteCustomNotification : RoomNotificationSettingsEvent
|
||||
data object ClearSetNotificationError : RoomNotificationSettingsEvent
|
||||
data object ClearRestoreDefaultError : RoomNotificationSettingsEvent
|
||||
}
|
||||
@@ -100,12 +100,12 @@ class RoomNotificationSettingsPresenter(
|
||||
!notificationSettingsService.canHomeServerPushEncryptedEventsToDevice().getOrDefault(true)
|
||||
}
|
||||
|
||||
fun handleEvent(event: RoomNotificationSettingsEvents) {
|
||||
fun handleEvent(event: RoomNotificationSettingsEvent) {
|
||||
when (event) {
|
||||
is RoomNotificationSettingsEvents.ChangeRoomNotificationMode -> {
|
||||
is RoomNotificationSettingsEvent.ChangeRoomNotificationMode -> {
|
||||
localCoroutineScope.setRoomNotificationMode(event.mode, pendingRoomNotificationMode, pendingSetDefault, setNotificationSettingAction)
|
||||
}
|
||||
is RoomNotificationSettingsEvents.SetNotificationMode -> {
|
||||
is RoomNotificationSettingsEvent.SetNotificationMode -> {
|
||||
if (event.isDefault) {
|
||||
localCoroutineScope.restoreDefaultRoomNotificationMode(restoreDefaultAction, pendingSetDefault)
|
||||
} else {
|
||||
@@ -114,13 +114,13 @@ class RoomNotificationSettingsPresenter(
|
||||
}
|
||||
}
|
||||
}
|
||||
is RoomNotificationSettingsEvents.DeleteCustomNotification -> {
|
||||
is RoomNotificationSettingsEvent.DeleteCustomNotification -> {
|
||||
localCoroutineScope.restoreDefaultRoomNotificationMode(restoreDefaultAction, pendingSetDefault)
|
||||
}
|
||||
RoomNotificationSettingsEvents.ClearSetNotificationError -> {
|
||||
RoomNotificationSettingsEvent.ClearSetNotificationError -> {
|
||||
setNotificationSettingAction.value = AsyncAction.Uninitialized
|
||||
}
|
||||
RoomNotificationSettingsEvents.ClearRestoreDefaultError -> {
|
||||
RoomNotificationSettingsEvent.ClearRestoreDefaultError -> {
|
||||
restoreDefaultAction.value = AsyncAction.Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ data class RoomNotificationSettingsState(
|
||||
val setNotificationSettingAction: AsyncAction<Unit>,
|
||||
val restoreDefaultAction: AsyncAction<Unit>,
|
||||
val displayMentionsOnlyDisclaimer: Boolean,
|
||||
val eventSink: (RoomNotificationSettingsEvents) -> Unit
|
||||
val eventSink: (RoomNotificationSettingsEvent) -> Unit
|
||||
)
|
||||
|
||||
val RoomNotificationSettingsState.displayNotificationMode: RoomNotificationMode? get() {
|
||||
|
||||
@@ -85,7 +85,7 @@ private fun RoomSpecificNotificationSettingsView(
|
||||
PreferenceSwitch(
|
||||
isChecked = !state.displayIsDefault.orTrue(),
|
||||
onCheckedChange = {
|
||||
state.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(!it))
|
||||
state.eventSink(RoomNotificationSettingsEvent.SetNotificationMode(!it))
|
||||
},
|
||||
title = stringResource(id = R.string.screen_room_notification_settings_allow_custom),
|
||||
subtitle = stringResource(id = R.string.screen_room_notification_settings_allow_custom_footnote),
|
||||
@@ -138,7 +138,7 @@ private fun RoomSpecificNotificationSettingsView(
|
||||
enabled = !state.displayIsDefault.orTrue(),
|
||||
displayMentionsOnlyDisclaimer = state.displayMentionsOnlyDisclaimer,
|
||||
onSelectOption = {
|
||||
state.eventSink(RoomNotificationSettingsEvents.ChangeRoomNotificationMode(it.mode))
|
||||
state.eventSink(RoomNotificationSettingsEvent.ChangeRoomNotificationMode(it.mode))
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -148,14 +148,14 @@ private fun RoomSpecificNotificationSettingsView(
|
||||
async = state.setNotificationSettingAction,
|
||||
onSuccess = {},
|
||||
errorMessage = { stringResource(R.string.screen_notification_settings_edit_failed_updating_default_mode) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvents.ClearSetNotificationError) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvent.ClearSetNotificationError) },
|
||||
)
|
||||
|
||||
AsyncActionView(
|
||||
async = state.restoreDefaultAction,
|
||||
onSuccess = {},
|
||||
errorMessage = { stringResource(R.string.screen_notification_settings_edit_failed_updating_default_mode) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvents.ClearRestoreDefaultError) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvent.ClearRestoreDefaultError) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ fun UserDefinedRoomNotificationSettingsView(
|
||||
enabled = !state.displayIsDefault.orTrue(),
|
||||
displayMentionsOnlyDisclaimer = state.displayMentionsOnlyDisclaimer,
|
||||
onSelectOption = {
|
||||
state.eventSink(RoomNotificationSettingsEvents.ChangeRoomNotificationMode(it.mode))
|
||||
state.eventSink(RoomNotificationSettingsEvent.ChangeRoomNotificationMode(it.mode))
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -69,7 +69,7 @@ fun UserDefinedRoomNotificationSettingsView(
|
||||
headlineContent = { Text(stringResource(R.string.screen_room_notification_settings_edit_remove_setting)) },
|
||||
style = ListItemStyle.Destructive,
|
||||
onClick = {
|
||||
state.eventSink(RoomNotificationSettingsEvents.DeleteCustomNotification)
|
||||
state.eventSink(RoomNotificationSettingsEvent.DeleteCustomNotification)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -77,14 +77,14 @@ fun UserDefinedRoomNotificationSettingsView(
|
||||
async = state.setNotificationSettingAction,
|
||||
onSuccess = {},
|
||||
errorMessage = { stringResource(R.string.screen_notification_settings_edit_failed_updating_default_mode) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvents.ClearSetNotificationError) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvent.ClearSetNotificationError) },
|
||||
)
|
||||
|
||||
AsyncActionView(
|
||||
async = state.restoreDefaultAction,
|
||||
onSuccess = { onBackClick() },
|
||||
errorMessage = { stringResource(R.string.screen_notification_settings_edit_failed_updating_default_mode) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvents.ClearRestoreDefaultError) },
|
||||
onErrorDismiss = { state.eventSink(RoomNotificationSettingsEvent.ClearRestoreDefaultError) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class RoomMemberListPresenterTest {
|
||||
skipItems(1)
|
||||
val loadedState = awaitItem()
|
||||
assertThat(loadedState.showBannedSection).isTrue()
|
||||
loadedState.eventSink(RoomMemberListEvents.ChangeSelectedSection(SelectedSection.BANNED))
|
||||
loadedState.eventSink(RoomMemberListEvent.ChangeSelectedSection(SelectedSection.BANNED))
|
||||
val bannedSectionState = awaitItem()
|
||||
assertThat(bannedSectionState.selectedSection).isEqualTo(SelectedSection.BANNED)
|
||||
// Now update the room members to have no banned users
|
||||
@@ -188,7 +188,7 @@ class RoomMemberListPresenterTest {
|
||||
)
|
||||
presenter.test {
|
||||
skipItems(1)
|
||||
awaitItem().eventSink(RoomMemberListEvents.RoomMemberSelected(anInvitedVictor()))
|
||||
awaitItem().eventSink(RoomMemberListEvent.RoomMemberSelected(anInvitedVictor()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package io.element.android.features.roomdetails.impl.members.details
|
||||
|
||||
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.roomdetails.impl.aJoinedRoom
|
||||
import io.element.android.features.roomdetails.impl.members.aRoomMember
|
||||
@@ -89,9 +86,7 @@ class RoomMemberDetailsPresenterTest {
|
||||
val presenter = createRoomMemberDetailsPresenter(
|
||||
room = room,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.userName).isEqualTo("Alice")
|
||||
assertThat(initialState.avatarUrl).isEqualTo("Alice Avatar url")
|
||||
@@ -111,9 +106,7 @@ class RoomMemberDetailsPresenterTest {
|
||||
val presenter = createRoomMemberDetailsPresenter(
|
||||
room = room,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.userName).isEqualTo("Alice")
|
||||
assertThat(initialState.avatarUrl).isEqualTo("Profile avatar url")
|
||||
@@ -130,9 +123,7 @@ class RoomMemberDetailsPresenterTest {
|
||||
val presenter = createRoomMemberDetailsPresenter(
|
||||
room = room,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.userName).isEqualTo("Profile user name")
|
||||
assertThat(initialState.avatarUrl).isEqualTo("Profile avatar url")
|
||||
@@ -161,9 +152,7 @@ class RoomMemberDetailsPresenterTest {
|
||||
}
|
||||
},
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.userName).isNull()
|
||||
assertThat(initialState.avatarUrl).isNull()
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package io.element.android.features.roomdetails.impl.notificationsettings
|
||||
|
||||
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.roomdetails.impl.aJoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
@@ -20,6 +17,7 @@ import io.element.android.libraries.matrix.test.notificationsettings.FakeNotific
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.test
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
@@ -27,9 +25,7 @@ class RoomNotificationSettingsPresenterTest {
|
||||
@Test
|
||||
fun `present - initial state is created from room info`() = runTest {
|
||||
val presenter = createRoomNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.roomNotificationSettings.dataOrNull()).isNull()
|
||||
assertThat(initialState.defaultRoomNotificationMode).isNull()
|
||||
@@ -42,10 +38,8 @@ class RoomNotificationSettingsPresenterTest {
|
||||
@Test
|
||||
fun `present - notification mode changed`() = runTest {
|
||||
val presenter = createRoomNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
awaitItem().eventSink(RoomNotificationSettingsEvents.ChangeRoomNotificationMode(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY))
|
||||
presenter.test {
|
||||
awaitItem().eventSink(RoomNotificationSettingsEvent.ChangeRoomNotificationMode(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
it.roomNotificationSettings.dataOrNull()?.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||
}.last()
|
||||
@@ -58,9 +52,7 @@ class RoomNotificationSettingsPresenterTest {
|
||||
fun `present - observe notification mode changed`() = runTest {
|
||||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
val presenter = createRoomNotificationSettingsPresenter(notificationSettingsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
notificationSettingsService.setRoomNotificationMode(A_ROOM_ID, RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
it.roomNotificationSettings.dataOrNull()?.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||
@@ -74,11 +66,9 @@ class RoomNotificationSettingsPresenterTest {
|
||||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
notificationSettingsService.givenSetNotificationModeError(AN_EXCEPTION)
|
||||
val presenter = createRoomNotificationSettingsPresenter(notificationSettingsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(false))
|
||||
initialState.eventSink(RoomNotificationSettingsEvent.SetNotificationMode(false))
|
||||
val failedState = consumeItemsUntilPredicate {
|
||||
it.setNotificationSettingAction.isFailure()
|
||||
}.last()
|
||||
@@ -87,7 +77,7 @@ class RoomNotificationSettingsPresenterTest {
|
||||
assertThat(failedState.pendingSetDefault).isNull()
|
||||
assertThat(failedState.setNotificationSettingAction.isFailure()).isTrue()
|
||||
|
||||
failedState.eventSink(RoomNotificationSettingsEvents.ClearSetNotificationError)
|
||||
failedState.eventSink(RoomNotificationSettingsEvent.ClearSetNotificationError)
|
||||
|
||||
val errorClearedState = consumeItemsUntilPredicate {
|
||||
it.setNotificationSettingAction.isUninitialized()
|
||||
@@ -100,11 +90,9 @@ class RoomNotificationSettingsPresenterTest {
|
||||
fun `present - notification settings set custom`() = runTest {
|
||||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
val presenter = createRoomNotificationSettingsPresenter(notificationSettingsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(false))
|
||||
initialState.eventSink(RoomNotificationSettingsEvent.SetNotificationMode(false))
|
||||
skipItems(3)
|
||||
val defaultState = awaitItem()
|
||||
assertThat(defaultState.roomNotificationSettings.dataOrNull()?.isDefault).isFalse()
|
||||
@@ -115,12 +103,10 @@ class RoomNotificationSettingsPresenterTest {
|
||||
@Test
|
||||
fun `present - notification settings restore default`() = runTest {
|
||||
val presenter = createRoomNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomNotificationSettingsEvents.ChangeRoomNotificationMode(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY))
|
||||
initialState.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(true))
|
||||
initialState.eventSink(RoomNotificationSettingsEvent.ChangeRoomNotificationMode(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY))
|
||||
initialState.eventSink(RoomNotificationSettingsEvent.SetNotificationMode(true))
|
||||
val defaultState = consumeItemsUntilPredicate {
|
||||
it.roomNotificationSettings.dataOrNull()?.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||
}.last()
|
||||
@@ -134,17 +120,15 @@ class RoomNotificationSettingsPresenterTest {
|
||||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
notificationSettingsService.givenRestoreDefaultNotificationModeError(AN_EXCEPTION)
|
||||
val presenter = createRoomNotificationSettingsPresenter(notificationSettingsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomNotificationSettingsEvents.ChangeRoomNotificationMode(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY))
|
||||
initialState.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(true))
|
||||
initialState.eventSink(RoomNotificationSettingsEvent.ChangeRoomNotificationMode(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY))
|
||||
initialState.eventSink(RoomNotificationSettingsEvent.SetNotificationMode(true))
|
||||
val failedState = consumeItemsUntilPredicate {
|
||||
it.restoreDefaultAction.isFailure()
|
||||
}.last()
|
||||
assertThat(failedState.restoreDefaultAction.isFailure()).isTrue()
|
||||
failedState.eventSink(RoomNotificationSettingsEvents.ClearRestoreDefaultError)
|
||||
failedState.eventSink(RoomNotificationSettingsEvent.ClearRestoreDefaultError)
|
||||
|
||||
val errorClearedState = consumeItemsUntilPredicate {
|
||||
it.restoreDefaultAction.isUninitialized()
|
||||
@@ -161,9 +145,7 @@ class RoomNotificationSettingsPresenterTest {
|
||||
}
|
||||
val room = aJoinedRoom(notificationSettingsService = notificationService, isEncrypted = true)
|
||||
val presenter = createRoomNotificationSettingsPresenter(notificationService, room)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().displayMentionsOnlyDisclaimer).isTrue()
|
||||
}
|
||||
}
|
||||
@@ -175,9 +157,7 @@ class RoomNotificationSettingsPresenterTest {
|
||||
}
|
||||
val room = aJoinedRoom(notificationSettingsService = notificationService, isEncrypted = false)
|
||||
val presenter = createRoomNotificationSettingsPresenter(notificationService, room)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().displayMentionsOnlyDisclaimer).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user