Pinned events : add the PinnedMessagesTimeline feature classes and branch in the navigation
This commit is contained in:
parent
28c1e0ebc7
commit
44ccae3327
7 changed files with 307 additions and 2 deletions
|
|
@ -41,6 +41,7 @@ import io.element.android.features.messages.api.MessagesEntryPoint
|
||||||
import io.element.android.features.messages.impl.attachments.Attachment
|
import io.element.android.features.messages.impl.attachments.Attachment
|
||||||
import io.element.android.features.messages.impl.attachments.preview.AttachmentsPreviewNode
|
import io.element.android.features.messages.impl.attachments.preview.AttachmentsPreviewNode
|
||||||
import io.element.android.features.messages.impl.forward.ForwardMessagesNode
|
import io.element.android.features.messages.impl.forward.ForwardMessagesNode
|
||||||
|
import io.element.android.features.messages.impl.pinned.list.PinnedMessagesListNode
|
||||||
import io.element.android.features.messages.impl.report.ReportMessageNode
|
import io.element.android.features.messages.impl.report.ReportMessageNode
|
||||||
import io.element.android.features.messages.impl.timeline.debug.EventDebugInfoNode
|
import io.element.android.features.messages.impl.timeline.debug.EventDebugInfoNode
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
|
@ -81,7 +82,6 @@ import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
@ContributesNode(RoomScope::class)
|
@ContributesNode(RoomScope::class)
|
||||||
class MessagesFlowNode @AssistedInject constructor(
|
class MessagesFlowNode @AssistedInject constructor(
|
||||||
|
|
@ -148,6 +148,9 @@ class MessagesFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class EditPoll(val eventId: EventId) : NavTarget
|
data class EditPoll(val eventId: EventId) : NavTarget
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data object PinnedEvents : NavTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
private val callbacks = plugins<MessagesEntryPoint.Callback>()
|
private val callbacks = plugins<MessagesEntryPoint.Callback>()
|
||||||
|
|
@ -220,7 +223,7 @@ class MessagesFlowNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewAllPinnedEvents() {
|
override fun onViewAllPinnedEvents() {
|
||||||
Timber.d("On View All Pinned Events not implemented yet.")
|
backstack.push(NavTarget.PinnedEvents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val inputs = MessagesNode.Inputs(
|
val inputs = MessagesNode.Inputs(
|
||||||
|
|
@ -276,6 +279,9 @@ class MessagesFlowNode @AssistedInject constructor(
|
||||||
.params(CreatePollEntryPoint.Params(mode = CreatePollMode.EditPoll(eventId = navTarget.eventId)))
|
.params(CreatePollEntryPoint.Params(mode = CreatePollMode.EditPoll(eventId = navTarget.eventId)))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
NavTarget.PinnedEvents -> {
|
||||||
|
createNode<PinnedMessagesListNode>(buildContext)
|
||||||
|
}
|
||||||
NavTarget.Empty -> {
|
NavTarget.Empty -> {
|
||||||
node(buildContext) {}
|
node(buildContext) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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.impl.pinned.list
|
||||||
|
|
||||||
|
sealed interface PinnedMessagesListEvents
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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.impl.pinned.list
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
|
import com.bumble.appyx.core.node.Node
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
|
import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories
|
||||||
|
import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactories
|
||||||
|
import io.element.android.libraries.di.RoomScope
|
||||||
|
|
||||||
|
@ContributesNode(RoomScope::class)
|
||||||
|
class PinnedMessagesListNode @AssistedInject constructor(
|
||||||
|
@Assisted buildContext: BuildContext,
|
||||||
|
@Assisted plugins: List<Plugin>,
|
||||||
|
private val presenter: PinnedMessagesListPresenter,
|
||||||
|
private val timelineItemPresenterFactories: TimelineItemPresenterFactories,
|
||||||
|
) : Node(buildContext, plugins = plugins) {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun View(modifier: Modifier) {
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalTimelineItemPresenterFactories provides timelineItemPresenterFactories,
|
||||||
|
) {
|
||||||
|
val state = presenter.present()
|
||||||
|
PinnedMessagesListView(
|
||||||
|
state = state,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.impl.pinned.list
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
|
||||||
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PinnedMessagesListPresenter @Inject constructor(
|
||||||
|
private val room: MatrixRoom,
|
||||||
|
private val timelineItemsFactory: TimelineItemsFactory,
|
||||||
|
) : Presenter<PinnedMessagesListState> {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun present(): PinnedMessagesListState {
|
||||||
|
val timelineItems by timelineItemsFactory.collectItemsAsState()
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
val timeline = room.pinnedEventsTimeline().getOrNull() ?: return@LaunchedEffect
|
||||||
|
combine(timeline.timelineItems, room.membersStateFlow) { items, membersState ->
|
||||||
|
timelineItemsFactory.replaceWith(
|
||||||
|
timelineItems = items,
|
||||||
|
roomMembers = membersState.roomMembers().orEmpty()
|
||||||
|
)
|
||||||
|
items
|
||||||
|
}.launchIn(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handleEvents(event: PinnedMessagesListEvents) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return PinnedMessagesListState(
|
||||||
|
timelineItems = timelineItems,
|
||||||
|
eventSink = ::handleEvents
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.impl.pinned.list
|
||||||
|
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
data class PinnedMessagesListState(
|
||||||
|
val timelineItems: ImmutableList<TimelineItem>,
|
||||||
|
val eventSink: (PinnedMessagesListEvents) -> Unit
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.impl.pinned.list
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||||
|
import io.element.android.features.messages.impl.timeline.components.TimelineItemRow
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PinnedMessagesListView(
|
||||||
|
state: PinnedMessagesListState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
modifier = modifier,
|
||||||
|
) { padding ->
|
||||||
|
PinnedMessagesListContent(
|
||||||
|
state = state,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(padding)
|
||||||
|
.consumeWindowInsets(padding),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PinnedMessagesListContent(
|
||||||
|
state: PinnedMessagesListState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Box(modifier) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
state = rememberLazyListState(),
|
||||||
|
reverseLayout = true,
|
||||||
|
contentPadding = PaddingValues(vertical = 8.dp),
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
items = state.timelineItems,
|
||||||
|
contentType = { timelineItem -> timelineItem.contentType() },
|
||||||
|
key = { timelineItem -> timelineItem.identifier() },
|
||||||
|
) { timelineItem ->
|
||||||
|
TimelineItemRow(
|
||||||
|
timelineItem = timelineItem,
|
||||||
|
timelineRoomInfo = TimelineRoomInfo(
|
||||||
|
isDm = false,
|
||||||
|
name = null,
|
||||||
|
userHasPermissionToSendMessage = false,
|
||||||
|
userHasPermissionToSendReaction = false,
|
||||||
|
isCallOngoing = false,
|
||||||
|
),
|
||||||
|
renderReadReceipts = false,
|
||||||
|
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true &&
|
||||||
|
state.timelineItems.first().identifier() == timelineItem.identifier(),
|
||||||
|
focusedEventId = null,
|
||||||
|
onClick = {},
|
||||||
|
onLongClick = {},
|
||||||
|
onUserDataClick = { },
|
||||||
|
onLinkClick = {},
|
||||||
|
inReplyToClick = {},
|
||||||
|
onReactionClick = { _, _ -> },
|
||||||
|
onReactionLongClick = { _, _ -> },
|
||||||
|
onMoreReactionsClick = {},
|
||||||
|
onReadReceiptClick = {},
|
||||||
|
eventSink = {},
|
||||||
|
onSwipeToReply = {},
|
||||||
|
onJoinCallClick = {},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
fun PinnedMessagesTimelineViewPreview(@PreviewParameter(PinnedMessagesTimelineStateProvider::class) state: PinnedMessagesListState) =
|
||||||
|
ElementPreview {
|
||||||
|
PinnedMessagesListView(
|
||||||
|
state = state,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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.impl.pinned.list
|
||||||
|
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
|
open class PinnedMessagesTimelineStateProvider : PreviewParameterProvider<PinnedMessagesListState> {
|
||||||
|
override val values: Sequence<PinnedMessagesListState>
|
||||||
|
get() = sequenceOf(
|
||||||
|
pinnedMessagesListState(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pinnedMessagesListState(
|
||||||
|
timelineItems: List<TimelineItem> = emptyList(),
|
||||||
|
) = PinnedMessagesListState(
|
||||||
|
timelineItems = timelineItems.toImmutableList(),
|
||||||
|
eventSink = {}
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue