Browse Source

Hide add more reaction button if user do not have permission to send reaction #2093

Also:
 - move `userHasPermissionToSendMessage` to `TimelineRoomInfo`
 - remove `canReply` parameter which can be computed from other params.
pull/2115/head
Benoit Marty 9 months ago
parent
commit
7414dfaa4d
  1. 15
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt
  2. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt
  3. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt
  4. 1
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt
  5. 1
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt
  6. 4
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
  7. 1
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt
  8. 19
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsLayout.kt
  9. 29
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsView.kt
  10. 5
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt

15
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt

@ -98,6 +98,7 @@ class TimelinePresenter @AssistedInject constructor( @@ -98,6 +98,7 @@ class TimelinePresenter @AssistedInject constructor(
val paginationState by timeline.paginationState.collectAsState()
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value)
val userHasPermissionToSendReaction by room.canSendMessageAsState(type = MessageEventType.REACTION_SENT, updateKey = syncUpdateFlow.value)
val prevMostRecentItemId = rememberSaveable { mutableStateOf<String?>(null) }
val newItemState = remember { mutableStateOf(NewEventState.None) }
@ -175,12 +176,18 @@ class TimelinePresenter @AssistedInject constructor( @@ -175,12 +176,18 @@ class TimelinePresenter @AssistedInject constructor(
.launchIn(this)
}
val timelineRoomInfo by remember {
derivedStateOf {
TimelineRoomInfo(
isDirect = room.isDirect,
userHasPermissionToSendMessage = userHasPermissionToSendMessage,
userHasPermissionToSendReaction = userHasPermissionToSendReaction,
)
}
}
return TimelineState(
timelineRoomInfo = TimelineRoomInfo(
isDirect = room.isDirect
),
timelineRoomInfo = timelineRoomInfo,
highlightedEventId = highlightedEventId.value,
userHasPermissionToSendMessage = userHasPermissionToSendMessage,
paginationState = paginationState,
timelineItems = timelineItems,
showReadReceipts = readReceiptsEnabled,

3
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt

@ -30,7 +30,6 @@ data class TimelineState( @@ -30,7 +30,6 @@ data class TimelineState(
val timelineRoomInfo: TimelineRoomInfo,
val showReadReceipts: Boolean,
val highlightedEventId: EventId?,
val userHasPermissionToSendMessage: Boolean,
val paginationState: MatrixTimeline.PaginationState,
val newEventState: NewEventState,
val sessionState: SessionState,
@ -40,4 +39,6 @@ data class TimelineState( @@ -40,4 +39,6 @@ data class TimelineState(
@Immutable
data class TimelineRoomInfo(
val isDirect: Boolean,
val userHasPermissionToSendMessage: Boolean,
val userHasPermissionToSendReaction: Boolean,
)

3
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt

@ -55,7 +55,6 @@ fun aTimelineState(timelineItems: ImmutableList<TimelineItem> = persistentListOf @@ -55,7 +55,6 @@ fun aTimelineState(timelineItems: ImmutableList<TimelineItem> = persistentListOf
beginningOfRoomReached = false,
),
highlightedEventId = null,
userHasPermissionToSendMessage = true,
newEventState = NewEventState.None,
sessionState = aSessionState(
isSessionVerified = true,
@ -218,4 +217,6 @@ internal fun aTimelineRoomInfo( @@ -218,4 +217,6 @@ internal fun aTimelineRoomInfo(
isDirect: Boolean = false,
) = TimelineRoomInfo(
isDirect = isDirect,
userHasPermissionToSendMessage = true,
userHasPermissionToSendReaction = true,
)

1
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt

@ -123,7 +123,6 @@ fun TimelineView( @@ -123,7 +123,6 @@ fun TimelineView(
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true
&& state.timelineItems.first().identifier() == timelineItem.identifier(),
highlightedItem = state.highlightedEventId?.value,
userHasPermissionToSendMessage = state.userHasPermissionToSendMessage,
onClick = onMessageClicked,
onLongClick = onMessageLongClicked,
onUserDataClick = onUserDataClicked,

1
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt

@ -35,7 +35,6 @@ internal fun ATimelineItemEventRow( @@ -35,7 +35,6 @@ internal fun ATimelineItemEventRow(
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = isHighlighted,
canReply = true,
onClick = {},
onLongClick = {},
onUserDataClick = {},

4
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

@ -81,6 +81,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt @@ -81,6 +81,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
import io.element.android.features.messages.impl.timeline.model.event.canBeRepliedTo
import io.element.android.features.messages.impl.timeline.model.metadata
import io.element.android.libraries.androidutils.system.openUrlInExternalApp
import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
@ -112,7 +113,6 @@ fun TimelineItemEventRow( @@ -112,7 +113,6 @@ fun TimelineItemEventRow(
showReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
isHighlighted: Boolean,
canReply: Boolean,
onClick: () -> Unit,
onLongClick: () -> Unit,
onUserDataClick: (UserId) -> Unit,
@ -151,6 +151,7 @@ fun TimelineItemEventRow( @@ -151,6 +151,7 @@ fun TimelineItemEventRow(
} else {
Spacer(modifier = Modifier.height(2.dp))
}
val canReply = timelineRoomInfo.userHasPermissionToSendMessage && event.content.canBeRepliedTo()
if (canReply) {
val state: SwipeableActionsState = rememberSwipeableActionsState()
val offset = state.offset.floatValue
@ -335,6 +336,7 @@ private fun TimelineItemEventRowContent( @@ -335,6 +336,7 @@ private fun TimelineItemEventRowContent(
if (event.reactionsState.reactions.isNotEmpty()) {
TimelineItemReactionsView(
reactionsState = event.reactionsState,
userCanSendReaction = timelineRoomInfo.userHasPermissionToSendReaction,
isOutgoing = event.isMine,
onReactionClicked = onReactionClicked,
onReactionLongClicked = onReactionLongClicked,

1
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt

@ -131,7 +131,6 @@ private fun TimelineItemGroupedEventsRowContent( @@ -131,7 +131,6 @@ private fun TimelineItemGroupedEventsRowContent(
isLastOutgoingMessage = isLastOutgoingMessage,
highlightedItem = highlightedItem,
sessionState = sessionState,
userHasPermissionToSendMessage = false,
onClick = onClick,
onLongClick = onLongClick,
inReplyToClick = inReplyToClick,

19
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsLayout.kt

@ -26,8 +26,8 @@ import androidx.compose.ui.unit.Dp @@ -26,8 +26,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import io.element.android.features.messages.impl.R
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.utils.CommonDrawables
/**
@ -46,7 +46,7 @@ import io.element.android.libraries.designsystem.utils.CommonDrawables @@ -46,7 +46,7 @@ import io.element.android.libraries.designsystem.utils.CommonDrawables
@Composable
fun TimelineItemReactionsLayout(
expandButton: @Composable () -> Unit,
addMoreButton: @Composable () -> Unit,
addMoreButton: (@Composable () -> Unit)?,
modifier: Modifier = Modifier,
itemSpacing: Dp = 0.dp,
rowSpacing: Dp = 0.dp,
@ -82,21 +82,21 @@ fun TimelineItemReactionsLayout( @@ -82,21 +82,21 @@ fun TimelineItemReactionsLayout(
// Used to render the collapsed state, this takes the rows inputted and adds the extra button to the last row,
// removing only as many trailing reactions as needed to make space for it.
fun replaceTrailingItemsWithButtons(rowsIn: List<List<Placeable>>, expandButton: Placeable, addMoreButton: Placeable): List<List<Placeable>> {
fun replaceTrailingItemsWithButtons(rowsIn: List<List<Placeable>>, expandButton: Placeable, addMoreButton: Placeable?): List<List<Placeable>> {
val rows = rowsIn.toMutableList()
val lastRow = rows.last()
val buttonsWidth = expandButton.width + itemSpacing.toPx().toInt() + addMoreButton.width
val buttonsWidth = expandButton.width + itemSpacing.toPx().toInt() + (addMoreButton?.width ?: 0)
var rowX = 0
lastRow.forEachIndexed { i, placeable ->
val horizontalSpacing = if (i == 0) 0 else itemSpacing.toPx().toInt()
rowX += placeable.width + horizontalSpacing
if (rowX > constraints.maxWidth - (buttonsWidth + horizontalSpacing)) {
val lastRowWithButton = lastRow.take(i) + listOf(expandButton, addMoreButton)
val lastRowWithButton = lastRow.take(i) + listOfNotNull(expandButton, addMoreButton)
rows[rows.size - 1] = lastRowWithButton
return rows
}
}
val lastRowWithButton = lastRow + listOf(expandButton, addMoreButton)
val lastRowWithButton = lastRow + listOfNotNull(expandButton, addMoreButton)
rows[rows.size - 1] = lastRowWithButton
return rows
}
@ -155,16 +155,15 @@ fun TimelineItemReactionsLayout( @@ -155,16 +155,15 @@ fun TimelineItemReactionsLayout(
val newConstrains = constraints.copy(minHeight = maxHeight)
reactionsPlaceables = subcompose(2, reactions).map { it.measure(newConstrains) }
expandPlaceable = subcompose(3, expandButton).first().measure(newConstrains)
val addMorePlaceable = subcompose(4, addMoreButton).first().measure(newConstrains)
val addMorePlaceable = addMoreButton?.let { subcompose(4, addMoreButton).first().measure(newConstrains) }
// Calculate the layout of the rows with the reactions button and add more button
val reactionsAndAddMore = calculateRows(reactionsPlaceables + listOf(addMorePlaceable))
val reactionsAndAddMore = calculateRows(reactionsPlaceables + listOfNotNull(addMorePlaceable))
// If we have extended beyond the defined number of rows we are showing the expand/collapse ui
if (rowsBeforeCollapsible?.let { reactionsAndAddMore.size > it } == true) {
if (expanded) {
// Show all subviews with the add more button at the end
var reactionsAndButtons = calculateRows(reactionsPlaceables + listOf(expandPlaceable, addMorePlaceable))
var reactionsAndButtons = calculateRows(reactionsPlaceables + listOfNotNull(expandPlaceable, addMorePlaceable))
reactionsAndButtons = ensureCollapseAndAddMoreButtonsAreOnTheSameRow(reactionsAndButtons)
layoutRows(reactionsAndButtons)
} else {

29
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsView.kt

@ -31,8 +31,8 @@ import io.element.android.features.messages.impl.R @@ -31,8 +31,8 @@ import io.element.android.features.messages.impl.R
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
import io.element.android.features.messages.impl.timeline.model.AggregatedReaction
import io.element.android.features.messages.impl.timeline.model.TimelineItemReactions
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.utils.CommonDrawables
import kotlinx.collections.immutable.ImmutableList
@ -40,6 +40,7 @@ import kotlinx.collections.immutable.ImmutableList @@ -40,6 +40,7 @@ import kotlinx.collections.immutable.ImmutableList
fun TimelineItemReactionsView(
reactionsState: TimelineItemReactions,
isOutgoing: Boolean,
userCanSendReaction: Boolean,
onReactionClicked: (emoji: String) -> Unit,
onReactionLongClicked: (emoji: String) -> Unit,
onMoreReactionsClicked: () -> Unit,
@ -49,6 +50,7 @@ fun TimelineItemReactionsView( @@ -49,6 +50,7 @@ fun TimelineItemReactionsView(
TimelineItemReactionsView(
modifier = modifier,
reactions = reactionsState.reactions,
userCanSendReaction = userCanSendReaction,
expanded = expanded,
isOutgoing = isOutgoing,
onReactionClick = onReactionClicked,
@ -61,6 +63,7 @@ fun TimelineItemReactionsView( @@ -61,6 +63,7 @@ fun TimelineItemReactionsView(
@Composable
private fun TimelineItemReactionsView(
reactions: ImmutableList<AggregatedReaction>,
userCanSendReaction: Boolean,
isOutgoing: Boolean,
expanded: Boolean,
onReactionClick: (emoji: String) -> Unit,
@ -93,19 +96,26 @@ private fun TimelineItemReactionsView( @@ -93,19 +96,26 @@ private fun TimelineItemReactionsView(
onLongClick = {}
)
},
addMoreButton = {
MessagesReactionButton(
content = MessagesReactionsButtonContent.Icon(CommonDrawables.ic_add_reaction),
onClick = onMoreReactionsClick,
onLongClick = {}
)
},
addMoreButton = if (userCanSendReaction) {
{
MessagesReactionButton(
content = MessagesReactionsButtonContent.Icon(CommonDrawables.ic_add_reaction),
onClick = onMoreReactionsClick,
onLongClick = {}
)
}
} else null,
reactions = {
reactions.forEach { reaction ->
CompositionLocalProvider(LocalLayoutDirection provides currentLayout) {
MessagesReactionButton(
content = MessagesReactionsButtonContent.Reaction(reaction = reaction),
onClick = { onReactionClick(reaction.key) },
onClick = {
// Always allow user to redact their own reactions
if (reaction.isHighlighted || userCanSendReaction) {
onReactionClick(reaction.key)
}
},
onLongClick = { onReactionLongClick(reaction.key) }
)
}
@ -157,6 +167,7 @@ private fun ContentToPreview( @@ -157,6 +167,7 @@ private fun ContentToPreview(
reactionsState = TimelineItemReactions(
reactions
),
userCanSendReaction = true,
isOutgoing = isOutgoing,
onReactionClicked = {},
onReactionLongClicked = {},

5
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt

@ -18,11 +18,10 @@ package io.element.android.features.messages.impl.timeline.components @@ -18,11 +18,10 @@ package io.element.android.features.messages.impl.timeline.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.model.event.canBeRepliedTo
import io.element.android.features.messages.impl.timeline.session.SessionState
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
@ -34,7 +33,6 @@ internal fun TimelineItemRow( @@ -34,7 +33,6 @@ internal fun TimelineItemRow(
showReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
highlightedItem: String?,
userHasPermissionToSendMessage: Boolean,
sessionState: SessionState,
onUserDataClick: (UserId) -> Unit,
onClick: (TimelineItem.Event) -> Unit,
@ -77,7 +75,6 @@ internal fun TimelineItemRow( @@ -77,7 +75,6 @@ internal fun TimelineItemRow(
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = highlightedItem == timelineItem.identifier(),
canReply = userHasPermissionToSendMessage && timelineItem.content.canBeRepliedTo(),
onClick = { onClick(timelineItem) },
onLongClick = { onLongClick(timelineItem) },
onUserDataClick = onUserDataClick,

Loading…
Cancel
Save