ganfra
2 months ago
7 changed files with 307 additions and 2 deletions
@ -0,0 +1,19 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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…
Reference in new issue