RoomList: branch accept/decline invite actions

This commit is contained in:
ganfra 2024-04-15 22:04:23 +02:00
parent 26eaed5ea4
commit c102c5b436
9 changed files with 75 additions and 32 deletions

View file

@ -24,6 +24,8 @@ sealed interface RoomListEvents {
data object DismissRequestVerificationPrompt : RoomListEvents
data object DismissRecoveryKeyPrompt : RoomListEvents
data object ToggleSearchResults : RoomListEvents
data class AcceptInvite(val roomListRoomSummary: RoomListRoomSummary) : RoomListEvents
data class DeclineInvite(val roomListRoomSummary: RoomListRoomSummary) : RoomListEvents
data class ShowContextMenu(val roomListRoomSummary: RoomListRoomSummary) : RoomListEvents
sealed interface ContextMenuEvents : RoomListEvents

View file

@ -29,6 +29,7 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.MobileScreen
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.invite.api.response.AcceptDeclineInviteView
import io.element.android.features.roomlist.api.RoomListEntryPoint
import io.element.android.features.roomlist.impl.components.RoomListMenuAction
import io.element.android.libraries.deeplink.usecase.InviteFriendsUseCase
@ -43,6 +44,7 @@ class RoomListNode @AssistedInject constructor(
private val presenter: RoomListPresenter,
private val inviteFriendsUseCase: InviteFriendsUseCase,
private val analyticsService: AnalyticsService,
private val acceptDeclineInviteView: AcceptDeclineInviteView,
) : Node(buildContext, plugins = plugins) {
init {
lifecycle.subscribe(
@ -106,6 +108,13 @@ class RoomListNode @AssistedInject constructor(
onMenuActionClicked = { onMenuActionClicked(activity, it) },
onRoomDirectorySearchClicked = this::onRoomDirectorySearchClicked,
modifier = modifier,
)
) {
acceptDeclineInviteView.Render(
state = state.acceptDeclineInviteState,
onInviteAccepted = this::onRoomClicked,
onInviteDeclined = { },
modifier = Modifier
)
}
}
}

View file

@ -32,6 +32,9 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import im.vector.app.features.analytics.plan.Interaction
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.InviteData
import io.element.android.features.leaveroom.api.LeaveRoomEvent
import io.element.android.features.leaveroom.api.LeaveRoomPresenter
import io.element.android.features.networkmonitor.api.NetworkMonitor
@ -41,6 +44,7 @@ import io.element.android.features.roomlist.impl.datasource.InviteStateDataSourc
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
import io.element.android.features.roomlist.impl.migration.MigrationScreenState
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.features.roomlist.impl.search.RoomListSearchEvents
import io.element.android.features.roomlist.impl.search.RoomListSearchState
import io.element.android.libraries.architecture.AsyncData
@ -89,6 +93,7 @@ class RoomListPresenter @Inject constructor(
private val migrationScreenPresenter: Presenter<MigrationScreenState>,
private val sessionPreferencesStore: SessionPreferencesStore,
private val analyticsService: AnalyticsService,
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
) : Presenter<RoomListState> {
private val encryptionService: EncryptionService = client.encryptionService()
private val syncService: SyncService = client.syncService()
@ -101,6 +106,7 @@ class RoomListPresenter @Inject constructor(
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
val filtersState = filtersPresenter.present()
val searchState = searchPresenter.present()
val acceptDeclineInviteState = acceptDeclineInvitePresenter.present()
LaunchedEffect(Unit) {
roomListDataSource.launchIn(this)
@ -131,6 +137,16 @@ class RoomListPresenter @Inject constructor(
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 -> {
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.AcceptInvite(event.roomListRoomSummary.toInviteData())
)
}
is RoomListEvents.DeclineInvite -> {
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.DeclineInvite(event.roomListRoomSummary.toInviteData())
)
}
}
}
@ -148,6 +164,7 @@ class RoomListPresenter @Inject constructor(
filtersState = filtersState,
searchState = searchState,
contentState = contentState,
acceptDeclineInviteState = acceptDeclineInviteState,
eventSink = ::handleEvents,
)
}
@ -282,4 +299,10 @@ class RoomListPresenter @Inject constructor(
val extendedRange = IntRange(extendedRangeStart, extendedRangeEnd)
client.roomListService.updateAllRoomsVisibleRange(extendedRange)
}
private fun RoomListRoomSummary.toInviteData() = InviteData(
roomId = roomId,
roomName = name,
isDirect = isDirect,
)
}

View file

@ -17,6 +17,7 @@
package io.element.android.features.roomlist.impl
import androidx.compose.runtime.Immutable
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.leaveroom.api.LeaveRoomState
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
@ -37,6 +38,7 @@ data class RoomListState(
val filtersState: RoomListFiltersState,
val searchState: RoomListSearchState,
val contentState: RoomListContentState,
val acceptDeclineInviteState: AcceptDeclineInviteState,
val eventSink: (RoomListEvents) -> Unit,
) {
val displayFilters = filtersState.isFeatureEnabled && contentState is RoomListContentState.Rooms

View file

@ -17,6 +17,8 @@
package io.element.android.features.roomlist.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.anAcceptDeclineInviteState
import io.element.android.features.leaveroom.api.LeaveRoomState
import io.element.android.features.leaveroom.api.aLeaveRoomState
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
@ -65,6 +67,7 @@ internal fun aRoomListState(
searchState: RoomListSearchState = aRoomListSearchState(),
filtersState: RoomListFiltersState = aRoomListFiltersState(isFeatureEnabled = false),
contentState: RoomListContentState = aRoomsContentState(),
acceptDeclineInviteState: AcceptDeclineInviteState = anAcceptDeclineInviteState(),
eventSink: (RoomListEvents) -> Unit = {}
) = RoomListState(
matrixUser = matrixUser,
@ -76,6 +79,7 @@ internal fun aRoomListState(
filtersState = filtersState,
searchState = searchState,
contentState = contentState,
acceptDeclineInviteState = acceptDeclineInviteState,
eventSink = eventSink,
)

View file

@ -32,6 +32,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.invite.api.response.AcceptDeclineInviteView
import io.element.android.features.leaveroom.api.LeaveRoomView
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
import io.element.android.features.roomlist.impl.components.RoomListContentView
@ -60,17 +61,13 @@ fun RoomListView(
onMenuActionClicked: (RoomListMenuAction) -> Unit,
onRoomDirectorySearchClicked: () -> Unit,
modifier: Modifier = Modifier,
acceptDeclineInviteView: @Composable ()->Unit,
) {
ConnectivityIndicatorContainer(
modifier = modifier,
isOnline = state.hasNetworkConnection,
) { topPadding ->
Box {
fun onRoomLongClicked(
roomListRoomSummary: RoomListRoomSummary
) {
state.eventSink(RoomListEvents.ShowContextMenu(roomListRoomSummary))
}
if (state.contextMenu is RoomListState.ContextMenu.Shown) {
RoomListContextMenu(
@ -87,7 +84,6 @@ fun RoomListView(
state = state,
onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked,
onRoomClicked = onRoomClicked,
onRoomLongClicked = { onRoomLongClicked(it) },
onOpenSettings = onSettingsClicked,
onCreateRoomClicked = onCreateRoomClicked,
onInvitesClicked = onInvitesClicked,
@ -96,8 +92,8 @@ fun RoomListView(
// This overlaid view will only be visible when state.displaySearchResults is true
RoomListSearchView(
state = state.searchState,
eventSink = state.eventSink,
onRoomClicked = onRoomClicked,
onRoomLongClicked = { onRoomLongClicked(it) },
onRoomDirectorySearchClicked = onRoomDirectorySearchClicked,
modifier = Modifier
.statusBarsPadding()
@ -105,6 +101,7 @@ fun RoomListView(
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
)
acceptDeclineInviteView()
}
}
}
@ -115,7 +112,6 @@ private fun RoomListScaffold(
state: RoomListState,
onConfirmRecoveryKeyClicked: () -> Unit,
onRoomClicked: (RoomId) -> Unit,
onRoomLongClicked: (RoomListRoomSummary) -> Unit,
onOpenSettings: () -> Unit,
onCreateRoomClicked: () -> Unit,
onInvitesClicked: () -> Unit,
@ -153,7 +149,6 @@ private fun RoomListScaffold(
eventSink = state.eventSink,
onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked,
onRoomClicked = ::onRoomClicked,
onRoomLongClicked = onRoomLongClicked,
onCreateRoomClicked = onCreateRoomClicked,
onInvitesClicked = onInvitesClicked,
modifier = Modifier
@ -195,5 +190,6 @@ internal fun RoomListViewPreview(@PreviewParameter(RoomListStateProvider::class)
onRoomSettingsClicked = {},
onMenuActionClicked = {},
onRoomDirectorySearchClicked = {},
acceptDeclineInviteView = {},
)
}

View file

@ -75,7 +75,6 @@ fun RoomListContentView(
eventSink: (RoomListEvents) -> Unit,
onConfirmRecoveryKeyClicked: () -> Unit,
onRoomClicked: (RoomListRoomSummary) -> Unit,
onRoomLongClicked: (RoomListRoomSummary) -> Unit,
onCreateRoomClicked: () -> Unit,
onInvitesClicked: () -> Unit,
modifier: Modifier = Modifier,
@ -104,7 +103,6 @@ fun RoomListContentView(
eventSink = eventSink,
onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked,
onRoomClicked = onRoomClicked,
onRoomLongClicked = onRoomLongClicked,
onInvitesClicked = onInvitesClicked,
)
}
@ -161,7 +159,6 @@ private fun RoomsView(
eventSink: (RoomListEvents) -> Unit,
onConfirmRecoveryKeyClicked: () -> Unit,
onRoomClicked: (RoomListRoomSummary) -> Unit,
onRoomLongClicked: (RoomListRoomSummary) -> Unit,
onInvitesClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
@ -176,7 +173,6 @@ private fun RoomsView(
eventSink = eventSink,
onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked,
onRoomClicked = onRoomClicked,
onRoomLongClicked = onRoomLongClicked,
onInvitesClicked = onInvitesClicked,
modifier = modifier.fillMaxSize(),
)
@ -189,7 +185,6 @@ private fun RoomsViewList(
eventSink: (RoomListEvents) -> Unit,
onConfirmRecoveryKeyClicked: () -> Unit,
onRoomClicked: (RoomListRoomSummary) -> Unit,
onRoomLongClicked: (RoomListRoomSummary) -> Unit,
onInvitesClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
@ -242,7 +237,7 @@ private fun RoomsViewList(
RoomSummaryRow(
room = room,
onClick = onRoomClicked,
onLongClick = onRoomLongClicked,
eventSink = eventSink,
)
if (index != state.summaries.lastIndex) {
HorizontalDivider()
@ -305,7 +300,6 @@ internal fun RoomListContentViewPreview(@PreviewParameter(RoomListContentStatePr
eventSink = {},
onConfirmRecoveryKeyClicked = {},
onRoomClicked = {},
onRoomLongClicked = {},
onCreateRoomClicked = {},
onInvitesClicked = {}
)

View file

@ -46,6 +46,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.roomlist.impl.RoomListEvents
import io.element.android.features.roomlist.impl.model.DisplayType
import io.element.android.features.roomlist.impl.model.InviteSender
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
@ -66,6 +67,7 @@ import io.element.android.libraries.designsystem.theme.roomListRoomName
import io.element.android.libraries.designsystem.theme.unreadIndicator
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.ui.strings.CommonStrings
import timber.log.Timber
internal val minHeight = 84.dp
@ -73,7 +75,7 @@ internal val minHeight = 84.dp
internal fun RoomSummaryRow(
room: RoomListRoomSummary,
onClick: (RoomListRoomSummary) -> Unit,
onLongClick: (RoomListRoomSummary) -> Unit,
eventSink: (RoomListEvents) -> Unit,
modifier: Modifier = Modifier,
) {
when (room.type) {
@ -84,7 +86,9 @@ internal fun RoomSummaryRow(
RoomSummaryScaffoldRow(
room = room,
onClick = onClick,
onLongClick = onLongClick,
onLongClick = {
Timber.d("Long click on invite room")
},
modifier = modifier
) {
InviteNameAndIndicatorRow(name = room.name)
@ -94,14 +98,22 @@ internal fun RoomSummaryRow(
InviteSenderRow(sender = room.inviteSender)
}
Spacer(modifier = Modifier.height(12.dp))
InviteButtonsRow(onAcceptClicked = { }, onDeclineClicked = { })
InviteButtonsRow(
onAcceptClicked = {
eventSink(RoomListEvents.AcceptInvite(room))
},
onDeclineClicked = {
eventSink(RoomListEvents.DeclineInvite(room))
})
}
}
DisplayType.ROOM -> {
RoomSummaryScaffoldRow(
room = room,
onClick = onClick,
onLongClick = onLongClick,
onLongClick = {
eventSink(RoomListEvents.ShowContextMenu(room))
},
modifier = modifier
) {
NameAndTimestampRow(
@ -133,11 +145,11 @@ private fun RoomSummaryScaffoldRow(
Row(
modifier = modifier
.fillMaxWidth()
.heightIn(min = minHeight)
.then(clickModifier)
.padding(horizontal = 16.dp, vertical = 11.dp)
.height(IntrinsicSize.Min),
.fillMaxWidth()
.heightIn(min = minHeight)
.then(clickModifier)
.padding(horizontal = 16.dp, vertical = 11.dp)
.height(IntrinsicSize.Min),
) {
Avatar(room.avatarData)
Spacer(modifier = Modifier.width(16.dp))
@ -357,6 +369,6 @@ internal fun RoomSummaryRowPreview(@PreviewParameter(RoomListRoomSummaryProvider
RoomSummaryRow(
room = data,
onClick = {},
onLongClick = {}
eventSink = {},
)
}

View file

@ -44,6 +44,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.roomlist.impl.R
import io.element.android.features.roomlist.impl.RoomListEvents
import io.element.android.features.roomlist.impl.components.RoomSummaryRow
import io.element.android.features.roomlist.impl.contentType
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
@ -65,8 +66,8 @@ import io.element.android.libraries.ui.strings.CommonStrings
@Composable
internal fun RoomListSearchView(
state: RoomListSearchState,
eventSink: (RoomListEvents) -> Unit,
onRoomClicked: (RoomId) -> Unit,
onRoomLongClicked: (RoomListRoomSummary) -> Unit,
onRoomDirectorySearchClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
@ -90,7 +91,7 @@ internal fun RoomListSearchView(
RoomListSearchContent(
state = state,
onRoomClicked = onRoomClicked,
onRoomLongClicked = onRoomLongClicked,
eventSink = eventSink,
onRoomDirectorySearchClicked = onRoomDirectorySearchClicked,
)
}
@ -102,8 +103,8 @@ internal fun RoomListSearchView(
@Composable
private fun RoomListSearchContent(
state: RoomListSearchState,
eventSink: (RoomListEvents) -> Unit,
onRoomClicked: (RoomId) -> Unit,
onRoomLongClicked: (RoomListRoomSummary) -> Unit,
onRoomDirectorySearchClicked: () -> Unit,
) {
val borderColor = MaterialTheme.colorScheme.tertiary
@ -193,7 +194,7 @@ private fun RoomListSearchContent(
RoomSummaryRow(
room = room,
onClick = ::onRoomClicked,
onLongClick = onRoomLongClicked,
eventSink = eventSink,
)
}
}
@ -220,7 +221,7 @@ internal fun RoomListSearchResultContentPreview(@PreviewParameter(RoomListSearch
RoomListSearchContent(
state = state,
onRoomClicked = {},
onRoomLongClicked = {},
eventSink = {},
onRoomDirectorySearchClicked = {},
)
}