diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt index affead0b4c..7794dab216 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt @@ -128,6 +128,14 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( override fun onOpenRoom(roomId: RoomId) { callbacks.forEach { it.onOpenRoom(roomId) } } + + override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) { + callbacks.forEach { it.onPermalinkClick(data, pushToBackstack) } + } + + override fun onForwardedToSingleRoom(roomId: RoomId) { + callbacks.forEach { it.onForwardedToSingleRoom(roomId) } + } } return roomDetailsEntryPoint.nodeBuilder(this, buildContext) .params(RoomDetailsEntryPoint.Params(initialTarget)) @@ -138,27 +146,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { is NavTarget.Messages -> { - val callback = object : MessagesEntryPoint.Callback { - override fun onRoomDetailsClick() { - backstack.push(NavTarget.RoomDetails) - } - - override fun onUserDataClick(userId: UserId) { - backstack.push(NavTarget.RoomMemberDetails(userId)) - } - - override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) { - callbacks.forEach { it.onPermalinkClick(data, pushToBackstack) } - } - - override fun onForwardedToSingleRoom(roomId: RoomId) { - callbacks.forEach { it.onForwardedToSingleRoom(roomId) } - } - } - messagesEntryPoint.nodeBuilder(this, buildContext) - .params(MessagesEntryPoint.Params(navTarget.focusedEventId)) - .callback(callback) - .build() + createMessagesNode(buildContext, navTarget) } NavTarget.RoomDetails -> { createRoomDetailsNode(buildContext, RoomDetailsEntryPoint.InitialTarget.RoomDetails) @@ -172,6 +160,36 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( } } + private fun createMessagesNode( + buildContext: BuildContext, + navTarget: NavTarget.Messages, + ): Node { + val callback = object : MessagesEntryPoint.Callback { + override fun onRoomDetailsClick() { + backstack.push(NavTarget.RoomDetails) + } + + override fun onUserDataClick(userId: UserId) { + backstack.push(NavTarget.RoomMemberDetails(userId)) + } + + override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) { + callbacks.forEach { it.onPermalinkClick(data, pushToBackstack) } + } + + override fun onForwardedToSingleRoom(roomId: RoomId) { + callbacks.forEach { it.onForwardedToSingleRoom(roomId) } + } + } + val params = MessagesEntryPoint.Params( + MessagesEntryPoint.InitialTarget.Messages(navTarget.focusedEventId) + ) + return messagesEntryPoint.nodeBuilder(this, buildContext) + .params(params) + .callback(callback) + .build() + } + sealed interface NavTarget : Parcelable { @Parcelize data class Messages(val focusedEventId: EventId? = null) : NavTarget diff --git a/features/messages/api/build.gradle.kts b/features/messages/api/build.gradle.kts index 5e15d8f38d..4eff3ebcb5 100644 --- a/features/messages/api/build.gradle.kts +++ b/features/messages/api/build.gradle.kts @@ -16,6 +16,7 @@ plugins { id("io.element.android-compose-library") + id("kotlin-parcelize") } android { diff --git a/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/MessagesEntryPoint.kt b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/MessagesEntryPoint.kt index cff060ca42..43544998ba 100644 --- a/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/MessagesEntryPoint.kt +++ b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/MessagesEntryPoint.kt @@ -16,17 +16,27 @@ package io.element.android.features.messages.api +import android.os.Parcelable import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import io.element.android.libraries.architecture.FeatureEntryPoint +import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.permalink.PermalinkData +import kotlinx.parcelize.Parcelize interface MessagesEntryPoint : FeatureEntryPoint { - fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + + sealed interface InitialTarget : Parcelable { + @Parcelize + data class Messages(val focusedEventId: EventId?) : InitialTarget + + @Parcelize + data object PinnedMessages : InitialTarget + } interface NodeBuilder { fun params(params: Params): NodeBuilder @@ -34,14 +44,14 @@ interface MessagesEntryPoint : FeatureEntryPoint { fun build(): Node } - data class Params( - val focusedEventId: EventId?, - ) - interface Callback : Plugin { fun onRoomDetailsClick() fun onUserDataClick(userId: UserId) fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean = true) fun onForwardedToSingleRoom(roomId: RoomId) } + + data class Params(val initialTarget: InitialTarget) : NodeInputs + + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder } diff --git a/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/pinned/IsPinnedMessagesFeatureEnabled.kt b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/pinned/IsPinnedMessagesFeatureEnabled.kt new file mode 100644 index 0000000000..829683d89d --- /dev/null +++ b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/pinned/IsPinnedMessagesFeatureEnabled.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.api.pinned + +import androidx.compose.runtime.Composable + +fun interface IsPinnedMessagesFeatureEnabled { + @Composable + operator fun invoke(): Boolean +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt index 0f6a6358d3..73991cfda5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPoint.kt @@ -32,7 +32,7 @@ class DefaultMessagesEntryPoint @Inject constructor() : MessagesEntryPoint { return object : MessagesEntryPoint.NodeBuilder { override fun params(params: MessagesEntryPoint.Params): MessagesEntryPoint.NodeBuilder { - plugins += MessagesFlowNode.Inputs(focusedEventId = params.focusedEventId) + plugins += MessagesEntryPoint.Params(params.initialTarget) return this } @@ -47,3 +47,9 @@ class DefaultMessagesEntryPoint @Inject constructor() : MessagesEntryPoint { } } } + + +internal fun MessagesEntryPoint.InitialTarget.toNavTarget() = when (this) { + is MessagesEntryPoint.InitialTarget.Messages -> MessagesFlowNode.NavTarget.Messages(focusedEventId) + MessagesEntryPoint.InitialTarget.PinnedMessages -> MessagesFlowNode.NavTarget.PinnedMessagesList +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index feecc42661..9e32655927 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -105,7 +105,7 @@ class MessagesFlowNode @AssistedInject constructor( private val timelineController: TimelineController, ) : BaseFlowNode( backstack = BackStack( - initialElement = NavTarget.Messages(overriddenFocusedEventId = null), + initialElement = plugins.filterIsInstance().first().initialTarget.toNavTarget(), savedStateMap = buildContext.savedStateMap, ), overlay = Overlay( @@ -114,16 +114,13 @@ class MessagesFlowNode @AssistedInject constructor( buildContext = buildContext, plugins = plugins ) { - data class Inputs(val focusedEventId: EventId?) : NodeInputs - - private val inputs = inputs() sealed interface NavTarget : Parcelable { @Parcelize data object Empty : NavTarget @Parcelize - data class Messages(val overriddenFocusedEventId: EventId?) : NavTarget + data class Messages(val focusedEventId: EventId?) : NavTarget @Parcelize data class MediaViewer( @@ -157,7 +154,7 @@ class MessagesFlowNode @AssistedInject constructor( data class EditPoll(val eventId: EventId) : NavTarget @Parcelize - data object PinnedEvents : NavTarget + data object PinnedMessagesList : NavTarget } private val callbacks = plugins() @@ -236,12 +233,10 @@ class MessagesFlowNode @AssistedInject constructor( } override fun onViewAllPinnedEvents() { - backstack.push(NavTarget.PinnedEvents) + backstack.push(NavTarget.PinnedMessagesList) } } - val inputs = MessagesNode.Inputs( - focusedEventId = navTarget.overriddenFocusedEventId ?: inputs.focusedEventId, - ) + val inputs = MessagesNode.Inputs(focusedEventId = navTarget.focusedEventId) createNode(buildContext, listOf(callback, inputs)) } is NavTarget.MediaViewer -> { @@ -297,7 +292,7 @@ class MessagesFlowNode @AssistedInject constructor( .params(CreatePollEntryPoint.Params(mode = CreatePollMode.EditPoll(eventId = navTarget.eventId))) .build() } - NavTarget.PinnedEvents -> { + NavTarget.PinnedMessagesList -> { val callback = object : PinnedMessagesListNode.Callback { override fun onEventClick(event: TimelineItem.Event) { processEventClick(event) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/IsPinnedMessagesFeatureEnabled.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/IsPinnedMessagesFeatureEnabled.kt index 5ef5e2c793..71ae30c1a4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/IsPinnedMessagesFeatureEnabled.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/IsPinnedMessagesFeatureEnabled.kt @@ -23,6 +23,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.messages.api.pinned.IsPinnedMessagesFeatureEnabled import io.element.android.libraries.di.AppScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags @@ -30,11 +31,6 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import javax.inject.Inject -fun interface IsPinnedMessagesFeatureEnabled { - @Composable - operator fun invoke(): Boolean -} - @ContributesBinding(AppScope::class) class DefaultIsPinnedMessagesFeatureEnabled @Inject constructor( private val featureFlagService: FeatureFlagService, diff --git a/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt b/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt index bde560189b..7b027849c4 100644 --- a/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt +++ b/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt @@ -24,6 +24,7 @@ import io.element.android.libraries.architecture.FeatureEntryPoint import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.permalink.PermalinkData import kotlinx.parcelize.Parcelize interface RoomDetailsEntryPoint : FeatureEntryPoint { @@ -43,6 +44,8 @@ interface RoomDetailsEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onOpenGlobalNotificationSettings() fun onOpenRoom(roomId: RoomId) + fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) + fun onForwardedToSingleRoom(roomId: RoomId) } interface NodeBuilder { diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index 07302b4876..def1e0d2d5 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -61,6 +61,7 @@ dependencies { implementation(projects.features.userprofile.shared) implementation(projects.services.analytics.api) implementation(projects.features.poll.api) + implementation(projects.features.messages.api) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index 4a34d64ad0..0ab0608566 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -31,6 +31,7 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.anvilannotations.ContributesNode import io.element.android.features.call.api.CallType import io.element.android.features.call.api.ElementCallEntryPoint +import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.poll.api.history.PollHistoryEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint import io.element.android.features.roomdetails.impl.edit.RoomDetailsEditNode @@ -49,6 +50,7 @@ import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.mediaviewer.api.local.MediaInfo import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode @@ -64,6 +66,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( private val elementCallEntryPoint: ElementCallEntryPoint, private val room: MatrixRoom, private val analyticsService: AnalyticsService, + private val messagesEntryPoint: MessagesEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), @@ -105,6 +108,9 @@ class RoomDetailsFlowNode @AssistedInject constructor( @Parcelize data object AdminSettings : NavTarget + + @Parcelize + data object PinnedMessagesList : NavTarget } override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { @@ -139,6 +145,10 @@ class RoomDetailsFlowNode @AssistedInject constructor( backstack.push(NavTarget.AdminSettings) } + override fun openPinnedMessagesList() { + backstack.push(NavTarget.PinnedMessagesList) + } + override fun onJoinCall() { val inputs = CallType.RoomCall( sessionId = room.sessionId, @@ -224,6 +234,28 @@ class RoomDetailsFlowNode @AssistedInject constructor( is NavTarget.AdminSettings -> { createNode(buildContext) } + NavTarget.PinnedMessagesList -> { + val params = MessagesEntryPoint.Params( + MessagesEntryPoint.InitialTarget.PinnedMessages + ) + val callback = object : MessagesEntryPoint.Callback { + override fun onRoomDetailsClick() = Unit + + override fun onUserDataClick(userId: UserId) = Unit + + override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) { + plugins().forEach { it.onPermalinkClick(data, pushToBackstack) } + } + + override fun onForwardedToSingleRoom(roomId: RoomId) { + plugins().forEach { it.onForwardedToSingleRoom(roomId) } + } + } + return messagesEntryPoint.nodeBuilder(this, buildContext) + .params(params) + .callback(callback) + .build() + } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt index d55966315e..4c726ab194 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt @@ -55,6 +55,7 @@ class RoomDetailsNode @AssistedInject constructor( fun openAvatarPreview(name: String, url: String) fun openPollHistory() fun openAdminSettings() + fun openPinnedMessagesList() fun onJoinCall() } @@ -115,6 +116,10 @@ class RoomDetailsNode @AssistedInject constructor( callbacks.forEach { it.openAdminSettings() } } + private fun openPinnedMessages() { + callbacks.forEach { it.openPinnedMessagesList() } + } + @Composable override fun View(modifier: Modifier) { val context = LocalContext.current @@ -144,6 +149,9 @@ class RoomDetailsNode @AssistedInject constructor( openPollHistory = ::openPollHistory, openAdminSettings = this::openAdminSettings, onJoinCallClick = ::onJoinCall, + onPinnedMessagesClick = ::openPinnedMessages ) } + + } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index 163e466e1f..e086e15e42 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -29,6 +29,7 @@ import androidx.compose.runtime.rememberCoroutineScope import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomPresenter +import io.element.android.features.messages.api.pinned.IsPinnedMessagesFeatureEnabled import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.bool.orFalse @@ -67,6 +68,7 @@ class RoomDetailsPresenter @Inject constructor( private val leaveRoomPresenter: LeaveRoomPresenter, private val dispatchers: CoroutineDispatchers, private val analyticsService: AnalyticsService, + private val isPinnedMessagesFeatureEnabled: IsPinnedMessagesFeatureEnabled, ) : Presenter { @Composable override fun present(): RoomDetailsState { @@ -83,6 +85,9 @@ class RoomDetailsPresenter @Inject constructor( val isFavorite by remember { derivedStateOf { roomInfo?.isFavorite.orFalse() } } val isPublic by remember { derivedStateOf { roomInfo?.isPublic.orFalse() } } + val canShowPinnedMessages = isPinnedMessagesFeatureEnabled() + val pinnedMessagesCount by remember { derivedStateOf { roomInfo?.pinnedEventIds?.size ?: 0 } } + LaunchedEffect(Unit) { canShowNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings) if (canShowNotificationSettings.value) { @@ -156,6 +161,8 @@ class RoomDetailsPresenter @Inject constructor( displayRolesAndPermissionsSettings = !room.isDm && isUserAdmin, isPublic = isPublic, heroes = roomInfo?.heroes.orEmpty().toPersistentList(), + canShowPinnedMessages = canShowPinnedMessages, + pinnedMessagesCount = pinnedMessagesCount, eventSink = ::handleEvents, ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt index f6a63d70f5..0d3578db1d 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt @@ -46,6 +46,8 @@ data class RoomDetailsState( val displayRolesAndPermissionsSettings: Boolean, val isPublic: Boolean, val heroes: ImmutableList, + val canShowPinnedMessages: Boolean, + val pinnedMessagesCount: Int, val eventSink: (RoomDetailsEvent) -> Unit ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt index 45bdf3163d..f6cbebaf7c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt @@ -105,6 +105,8 @@ fun aRoomDetailsState( displayAdminSettings: Boolean = false, isPublic: Boolean = true, heroes: List = emptyList(), + canShowPinnedMessages: Boolean = true, + pinnedMessagesCount: Int = 3, eventSink: (RoomDetailsEvent) -> Unit = {}, ) = RoomDetailsState( roomId = roomId, @@ -126,6 +128,8 @@ fun aRoomDetailsState( displayRolesAndPermissionsSettings = displayAdminSettings, isPublic = isPublic, heroes = heroes.toPersistentList(), + canShowPinnedMessages = canShowPinnedMessages, + pinnedMessagesCount = pinnedMessagesCount, eventSink = eventSink ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index fc2a051dc6..2ef9e0718e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -103,6 +103,7 @@ fun RoomDetailsView( openPollHistory: () -> Unit, openAdminSettings: () -> Unit, onJoinCallClick: () -> Unit, + onPinnedMessagesClick: () -> Unit, modifier: Modifier = Modifier, ) { Scaffold( @@ -183,6 +184,13 @@ fun RoomDetailsView( } ) + if(state.canShowPinnedMessages) { + PinnedMessagesItem( + pinnedMessagesCount = state.pinnedMessagesCount, + onPinnedMessagesClick = onPinnedMessagesClick + ) + } + if (state.displayRolesAndPermissionsSettings) { ListItem( headlineContent = { Text(stringResource(R.string.screen_room_details_roles_and_permissions)) }, @@ -503,6 +511,19 @@ private fun MembersItem( ) } +@Composable +private fun PinnedMessagesItem( + pinnedMessagesCount: Int, + onPinnedMessagesClick: () -> Unit, +) { + ListItem( + headlineContent = { Text(stringResource(CommonStrings.screen_room_details_pinned_events_row_title)) }, + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Pin())), + trailingContent = ListItemContent.Text(pinnedMessagesCount.toString()), + onClick = onPinnedMessagesClick, + ) +} + @Composable private fun PollsSection( openPollHistory: () -> Unit, @@ -573,5 +594,6 @@ private fun ContentToPreview(state: RoomDetailsState) { openPollHistory = {}, openAdminSettings = {}, onJoinCallClick = {}, + onPinnedMessagesClick = {}, ) }