diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index ae324aab0e..411ff37c8f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -21,6 +21,7 @@ import dagger.assisted.AssistedInject import io.element.android.features.messages.api.pinned.IsPinnedMessagesFeatureEnabled import io.element.android.features.messages.impl.UserEventPermissions import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction +import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionComparator import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory @@ -70,6 +71,8 @@ class DefaultActionListPresenter @AssistedInject constructor( override fun create(postProcessor: TimelineItemActionPostProcessor): DefaultActionListPresenter } + private val comparator = TimelineItemActionComparator() + @Composable override fun present(): ActionListState { val localCoroutineScope = rememberCoroutineScope() @@ -137,7 +140,6 @@ class DefaultActionListPresenter @AssistedInject constructor( } } - // See order in https://www.figma.com/design/ux3tYoZV9WghC7hHT9Fhk0/Compound-iOS-Components?node-id=2946-2392 private suspend fun buildActions( timelineItem: TimelineItem.Event, usersEventPermissions: UserEventPermissions, @@ -146,7 +148,7 @@ class DefaultActionListPresenter @AssistedInject constructor( isEventPinned: Boolean, ): List { val canRedact = timelineItem.isMine && usersEventPermissions.canRedactOwn || !timelineItem.isMine && usersEventPermissions.canRedactOther - return buildList { + return buildSet { if (timelineItem.canBeRepliedTo && usersEventPermissions.canSendMessage) { if (timelineItem.isThreaded) { add(TimelineItemAction.ReplyInThread) @@ -202,6 +204,7 @@ class DefaultActionListPresenter @AssistedInject constructor( } } .postFilter(timelineItem.content) + .sortedWith(comparator) .let(postProcessor::process) } } @@ -209,7 +212,7 @@ class DefaultActionListPresenter @AssistedInject constructor( /** * Post filter the actions based on the content of the event. */ -private fun List.postFilter(content: TimelineItemEventContent): List { +private fun Iterable.postFilter(content: TimelineItemEventContent): Iterable { return filter { action -> when (content) { is TimelineItemCallNotifyContent, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt index 0323a2e6c6..a5f027a535 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt @@ -9,6 +9,7 @@ package io.element.android.features.messages.impl.actionlist import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction +import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionComparator import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure import io.element.android.features.messages.impl.crypto.sendfailure.resolve.anUnsignedDeviceSendFailure import io.element.android.features.messages.impl.timeline.aTimelineItemEvent @@ -22,7 +23,6 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVoiceContent import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList open class ActionListStateProvider : PreviewParameterProvider { @@ -175,7 +175,7 @@ fun anActionListState( fun aTimelineItemActionList( copyAction: TimelineItemAction? = TimelineItemAction.CopyText ): ImmutableList { - return listOfNotNull( + return setOfNotNull( TimelineItemAction.Reply, TimelineItemAction.Forward, copyAction, @@ -184,17 +184,19 @@ fun aTimelineItemActionList( TimelineItemAction.Redact, TimelineItemAction.ReportContent, TimelineItemAction.ViewSource, - ).toPersistentList() + ) + .sortedWith(TimelineItemActionComparator()) + .toPersistentList() } fun aTimelineItemPollActionList(): ImmutableList { - return persistentListOf( + return setOf( TimelineItemAction.EndPoll, TimelineItemAction.Reply, - TimelineItemAction.CopyText, + TimelineItemAction.Pin, TimelineItemAction.CopyLink, - TimelineItemAction.ViewSource, - TimelineItemAction.ReportContent, TimelineItemAction.Redact, ) + .sortedWith(TimelineItemActionComparator()) + .toPersistentList() } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemActionComparator.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemActionComparator.kt new file mode 100644 index 0000000000..8eef2d7619 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemActionComparator.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.features.messages.impl.actionlist.model + +class TimelineItemActionComparator : Comparator { + // See order in https://www.figma.com/design/ux3tYoZV9WghC7hHT9Fhk0/Compound-iOS-Components?node-id=2946-2392 + private val orderedList = listOf( + TimelineItemAction.EndPoll, + TimelineItemAction.ViewInTimeline, + TimelineItemAction.Reply, + TimelineItemAction.ReplyInThread, + TimelineItemAction.Forward, + TimelineItemAction.Pin, + TimelineItemAction.Unpin, + TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, + TimelineItemAction.AddCaption, + TimelineItemAction.EditCaption, + TimelineItemAction.CopyCaption, + TimelineItemAction.RemoveCaption, + TimelineItemAction.ViewSource, + TimelineItemAction.ReportContent, + TimelineItemAction.Redact, + ) + + override fun compare(o1: TimelineItemAction, o2: TimelineItemAction): Int { + val index1 = orderedList.indexOf(o1) + val index2 = orderedList.indexOf(o2) + return index1.compareTo(index2) + } +} diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index 1e4b92d91d..49db6f6c95 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -176,8 +176,8 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) @@ -221,8 +221,8 @@ class ActionListPresenterTest { TimelineItemAction.ReplyInThread, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) @@ -268,8 +268,8 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) @@ -314,8 +314,8 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, TimelineItemAction.Redact, @@ -361,8 +361,8 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, TimelineItemAction.Redact, @@ -408,10 +408,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -453,10 +453,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.ReplyInThread, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -501,10 +501,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, ) ) @@ -547,9 +547,9 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.AddCaption, TimelineItemAction.Pin, TimelineItemAction.CopyLink, + TimelineItemAction.AddCaption, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -646,11 +646,11 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.Pin, + TimelineItemAction.CopyLink, TimelineItemAction.EditCaption, TimelineItemAction.CopyCaption, TimelineItemAction.RemoveCaption, - TimelineItemAction.Pin, - TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -696,11 +696,11 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.CopyCaption, TimelineItemAction.Pin, TimelineItemAction.CopyLink, + TimelineItemAction.CopyCaption, TimelineItemAction.ViewSource, - TimelineItemAction.Redact, + TimelineItemAction.ReportContent, ) ) ) @@ -813,10 +813,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.Redact, ) ) @@ -860,9 +860,9 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.CopyLink, TimelineItemAction.Edit, TimelineItemAction.CopyText, - TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -914,10 +914,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Unpin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -1049,11 +1049,11 @@ class ActionListPresenterTest { displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, actions = persistentListOf( - TimelineItemAction.Reply, - TimelineItemAction.Edit, TimelineItemAction.EndPoll, + TimelineItemAction.Reply, TimelineItemAction.Pin, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, TimelineItemAction.Redact, ) ) @@ -1092,8 +1092,8 @@ class ActionListPresenterTest { displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, actions = persistentListOf( - TimelineItemAction.Reply, TimelineItemAction.EndPoll, + TimelineItemAction.Reply, TimelineItemAction.Pin, TimelineItemAction.CopyLink, TimelineItemAction.Redact,