Pinned events : handle loading/error on banner
This commit is contained in:
@@ -23,7 +23,7 @@ import io.element.android.features.messages.impl.messagecomposer.AttachmentsStat
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
|
||||
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
|
||||
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
|
||||
import io.element.android.features.messages.impl.pinned.banner.aPinnedMessagesBannerState
|
||||
import io.element.android.features.messages.impl.pinned.banner.aLoadedPinnedMessagesBannerState
|
||||
import io.element.android.features.messages.impl.timeline.TimelineState
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemList
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineState
|
||||
@@ -90,8 +90,8 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
||||
callState = RoomCallState.DISABLED,
|
||||
),
|
||||
aMessagesState(
|
||||
pinnedMessagesBannerState = aPinnedMessagesBannerState(
|
||||
pinnedMessagesCount = 4,
|
||||
pinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(
|
||||
knownPinnedMessagesCount = 4,
|
||||
currentPinnedMessageIndex = 0,
|
||||
),
|
||||
),
|
||||
@@ -121,7 +121,7 @@ fun aMessagesState(
|
||||
showReinvitePrompt: Boolean = false,
|
||||
enableVoiceMessages: Boolean = true,
|
||||
callState: RoomCallState = RoomCallState.ENABLED,
|
||||
pinnedMessagesBannerState: PinnedMessagesBannerState = aPinnedMessagesBannerState(),
|
||||
pinnedMessagesBannerState: PinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(),
|
||||
eventSink: (MessagesEvents) -> Unit = {},
|
||||
) = MessagesState(
|
||||
roomId = RoomId("!id:domain"),
|
||||
|
||||
@@ -71,6 +71,7 @@ import io.element.android.features.messages.impl.messagecomposer.AttachmentsBott
|
||||
import io.element.android.features.messages.impl.messagecomposer.AttachmentsState
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerView
|
||||
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
|
||||
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerView
|
||||
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerViewDefaults
|
||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||
@@ -400,7 +401,7 @@ private fun MessagesViewContent(
|
||||
nestedScrollConnection = scrollBehavior.nestedScrollConnection,
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = state.pinnedMessagesBannerState.displayBanner && scrollBehavior.isVisible,
|
||||
visible = state.pinnedMessagesBannerState != PinnedMessagesBannerState.Hidden && scrollBehavior.isVisible,
|
||||
enter = expandVertically(),
|
||||
exit = shrinkVertically(),
|
||||
) {
|
||||
|
||||
@@ -26,10 +26,14 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -43,29 +47,34 @@ class PinnedMessagesBannerPresenter @Inject constructor(
|
||||
private val room: MatrixRoom,
|
||||
private val itemFactory: PinnedMessagesBannerItemFactory,
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
private val networkMonitor: NetworkMonitor,
|
||||
) : Presenter<PinnedMessagesBannerState> {
|
||||
@Composable
|
||||
override fun present(): PinnedMessagesBannerState {
|
||||
val isFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.PinnedEvents).collectAsState(initial = false)
|
||||
var timelineFailed by rememberSaveable { mutableStateOf(false) }
|
||||
var pinnedItems by remember {
|
||||
mutableStateOf<List<PinnedMessagesBannerItem>>(emptyList())
|
||||
mutableStateOf<ImmutableList<PinnedMessagesBannerItem>>(persistentListOf())
|
||||
}
|
||||
val knownPinnedMessagesCount by remember {
|
||||
room.roomInfoFlow.map { roomInfo -> roomInfo.pinnedEventIds.size }
|
||||
}.collectAsState(initial = null)
|
||||
|
||||
fun onItemsChange(newItems: List<PinnedMessagesBannerItem>) {
|
||||
pinnedItems = newItems
|
||||
}
|
||||
var currentPinnedMessageIndex by rememberSaveable { mutableIntStateOf(0) }
|
||||
|
||||
var currentPinnedMessageIndex by rememberSaveable {
|
||||
mutableIntStateOf(0)
|
||||
}
|
||||
|
||||
LaunchedEffect(pinnedItems) {
|
||||
val pinnedMessageCount = pinnedItems.size
|
||||
if (currentPinnedMessageIndex >= pinnedMessageCount) {
|
||||
currentPinnedMessageIndex = (pinnedMessageCount - 1).coerceAtLeast(0)
|
||||
PinnedMessagesBannerItemsEffect(
|
||||
isFeatureEnabled = isFeatureEnabled,
|
||||
onItemsChange = { newItems ->
|
||||
val pinnedMessageCount = newItems.size
|
||||
if (currentPinnedMessageIndex >= pinnedMessageCount) {
|
||||
currentPinnedMessageIndex = 0
|
||||
}
|
||||
pinnedItems = newItems
|
||||
},
|
||||
onTimelineFail = { hasTimelineFailed ->
|
||||
timelineFailed = hasTimelineFailed
|
||||
}
|
||||
}
|
||||
|
||||
PinnedMessagesBannerItemsEffect(::onItemsChange)
|
||||
)
|
||||
|
||||
fun handleEvent(event: PinnedMessagesBannerEvents) {
|
||||
when (event) {
|
||||
@@ -79,32 +88,68 @@ class PinnedMessagesBannerPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
return PinnedMessagesBannerState(
|
||||
pinnedMessagesCount = pinnedItems.size,
|
||||
currentPinnedMessage = pinnedItems.getOrNull(currentPinnedMessageIndex),
|
||||
return pinnedMessagesBannerState(
|
||||
isFeatureEnabled = isFeatureEnabled,
|
||||
hasTimelineFailed = timelineFailed,
|
||||
realPinnedMessagesCount = knownPinnedMessagesCount,
|
||||
pinnedItems = pinnedItems,
|
||||
currentPinnedMessageIndex = currentPinnedMessageIndex,
|
||||
eventSink = ::handleEvent
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun pinnedMessagesBannerState(
|
||||
isFeatureEnabled: Boolean,
|
||||
hasTimelineFailed: Boolean,
|
||||
realPinnedMessagesCount: Int?,
|
||||
pinnedItems: ImmutableList<PinnedMessagesBannerItem>,
|
||||
currentPinnedMessageIndex: Int,
|
||||
eventSink: (PinnedMessagesBannerEvents) -> Unit
|
||||
): PinnedMessagesBannerState {
|
||||
val currentPinnedMessage = pinnedItems.getOrNull(currentPinnedMessageIndex)
|
||||
return when {
|
||||
!isFeatureEnabled -> PinnedMessagesBannerState.Hidden
|
||||
hasTimelineFailed -> PinnedMessagesBannerState.Hidden
|
||||
realPinnedMessagesCount == null || realPinnedMessagesCount == 0 -> PinnedMessagesBannerState.Hidden
|
||||
currentPinnedMessage == null -> PinnedMessagesBannerState.Loading(realPinnedMessagesCount = realPinnedMessagesCount)
|
||||
else -> {
|
||||
PinnedMessagesBannerState.Loaded(
|
||||
currentPinnedMessage = currentPinnedMessage,
|
||||
currentPinnedMessageIndex = currentPinnedMessageIndex,
|
||||
knownPinnedMessagesCount = realPinnedMessagesCount,
|
||||
eventSink = eventSink
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
@Composable
|
||||
private fun PinnedMessagesBannerItemsEffect(
|
||||
onItemsChange: (List<PinnedMessagesBannerItem>) -> Unit,
|
||||
isFeatureEnabled: Boolean,
|
||||
onItemsChange: (ImmutableList<PinnedMessagesBannerItem>) -> Unit,
|
||||
onTimelineFail: (Boolean) -> Unit,
|
||||
) {
|
||||
val isFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.PinnedEvents).collectAsState(initial = false)
|
||||
val updatedOnItemsChange by rememberUpdatedState(onItemsChange)
|
||||
val updatedOnTimelineFail by rememberUpdatedState(onTimelineFail)
|
||||
val networkStatus by networkMonitor.connectivity.collectAsState()
|
||||
|
||||
LaunchedEffect(isFeatureEnabled) {
|
||||
LaunchedEffect(isFeatureEnabled, networkStatus) {
|
||||
if (!isFeatureEnabled) return@LaunchedEffect
|
||||
|
||||
val pinnedEventsTimeline = room.pinnedEventsTimeline().getOrNull() ?: return@LaunchedEffect
|
||||
val pinnedEventsTimeline = room.pinnedEventsTimeline()
|
||||
.onFailure { updatedOnTimelineFail(true) }
|
||||
.onSuccess { updatedOnTimelineFail(false) }
|
||||
.getOrNull()
|
||||
?: return@LaunchedEffect
|
||||
|
||||
pinnedEventsTimeline.timelineItems
|
||||
.debounce(300.milliseconds)
|
||||
.map { timelineItems ->
|
||||
timelineItems.mapNotNull { timelineItem ->
|
||||
itemFactory.create(timelineItem)
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
.onEach { newItems ->
|
||||
updatedOnItemsChange(newItems)
|
||||
|
||||
@@ -16,11 +16,40 @@
|
||||
|
||||
package io.element.android.features.messages.impl.pinned.banner
|
||||
|
||||
data class PinnedMessagesBannerState(
|
||||
val pinnedMessagesCount: Int,
|
||||
val currentPinnedMessageIndex: Int,
|
||||
val currentPinnedMessage: PinnedMessagesBannerItem?,
|
||||
val eventSink: (PinnedMessagesBannerEvents) -> Unit
|
||||
) {
|
||||
val displayBanner = pinnedMessagesCount > 0 && currentPinnedMessage != null
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import io.element.android.libraries.designsystem.text.toAnnotatedString
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Immutable
|
||||
sealed interface PinnedMessagesBannerState {
|
||||
data object Hidden : PinnedMessagesBannerState
|
||||
data class Loading(val realPinnedMessagesCount: Int) : PinnedMessagesBannerState
|
||||
data class Loaded(
|
||||
val currentPinnedMessage: PinnedMessagesBannerItem,
|
||||
val currentPinnedMessageIndex: Int,
|
||||
val knownPinnedMessagesCount: Int,
|
||||
val eventSink: (PinnedMessagesBannerEvents) -> Unit
|
||||
) : PinnedMessagesBannerState
|
||||
|
||||
fun pinnedMessagesCount() = when (this) {
|
||||
is Hidden -> 0
|
||||
is Loading -> realPinnedMessagesCount
|
||||
is Loaded -> knownPinnedMessagesCount
|
||||
}
|
||||
|
||||
fun currentPinnedMessageIndex() = when (this) {
|
||||
is Hidden -> 0
|
||||
is Loading -> 0
|
||||
is Loaded -> currentPinnedMessageIndex
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun formattedMessage() = when (this) {
|
||||
is Hidden -> AnnotatedString("")
|
||||
is Loading -> stringResource(id = CommonStrings.screen_room_pinned_banner_loading_description).toAnnotatedString()
|
||||
is Loaded -> currentPinnedMessage.formatted
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,26 +24,38 @@ import kotlin.random.Random
|
||||
internal class PinnedMessagesBannerStateProvider : PreviewParameterProvider<PinnedMessagesBannerState> {
|
||||
override val values: Sequence<PinnedMessagesBannerState>
|
||||
get() = sequenceOf(
|
||||
aPinnedMessagesBannerState(pinnedMessagesCount = 1, currentPinnedMessageIndex = 0),
|
||||
aPinnedMessagesBannerState(pinnedMessagesCount = 2, currentPinnedMessageIndex = 0),
|
||||
aPinnedMessagesBannerState(pinnedMessagesCount = 4, currentPinnedMessageIndex = 0),
|
||||
aPinnedMessagesBannerState(pinnedMessagesCount = 4, currentPinnedMessageIndex = 1),
|
||||
aPinnedMessagesBannerState(pinnedMessagesCount = 4, currentPinnedMessageIndex = 2),
|
||||
aPinnedMessagesBannerState(pinnedMessagesCount = 4, currentPinnedMessageIndex = 3),
|
||||
aHiddenPinnedMessagesBannerState(),
|
||||
aLoadingPinnedMessagesBannerState(knownPinnedMessagesCount = 1),
|
||||
aLoadingPinnedMessagesBannerState(knownPinnedMessagesCount = 4),
|
||||
aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 1, currentPinnedMessageIndex = 0),
|
||||
aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 2, currentPinnedMessageIndex = 0),
|
||||
aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 3, currentPinnedMessageIndex = 0),
|
||||
aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 0),
|
||||
aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 1),
|
||||
aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 2),
|
||||
aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 3),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aPinnedMessagesBannerState(
|
||||
pinnedMessagesCount: Int = 0,
|
||||
currentPinnedMessageIndex: Int = -1,
|
||||
internal fun aHiddenPinnedMessagesBannerState() = PinnedMessagesBannerState.Hidden
|
||||
|
||||
internal fun aLoadingPinnedMessagesBannerState(
|
||||
knownPinnedMessagesCount: Int = 4
|
||||
) = PinnedMessagesBannerState.Loading(
|
||||
realPinnedMessagesCount = knownPinnedMessagesCount
|
||||
)
|
||||
|
||||
internal fun aLoadedPinnedMessagesBannerState(
|
||||
currentPinnedMessageIndex: Int = 0,
|
||||
knownPinnedMessagesCount: Int = 1,
|
||||
currentPinnedMessage: PinnedMessagesBannerItem = PinnedMessagesBannerItem(
|
||||
eventId = EventId("\$" + Random.nextInt().toString()),
|
||||
formatted = AnnotatedString("This is a pinned message")
|
||||
),
|
||||
eventSink: (PinnedMessagesBannerEvents) -> Unit = {}
|
||||
) = PinnedMessagesBannerState(
|
||||
pinnedMessagesCount = pinnedMessagesCount,
|
||||
currentPinnedMessageIndex = currentPinnedMessageIndex,
|
||||
) = PinnedMessagesBannerState.Loaded(
|
||||
currentPinnedMessage = currentPinnedMessage,
|
||||
currentPinnedMessageIndex = currentPinnedMessageIndex,
|
||||
knownPinnedMessagesCount = knownPinnedMessagesCount,
|
||||
eventSink = eventSink
|
||||
)
|
||||
|
||||
@@ -71,42 +71,52 @@ fun PinnedMessagesBannerView(
|
||||
onViewAllClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (state.currentPinnedMessage == null) return
|
||||
Box(modifier = modifier) {
|
||||
when (state) {
|
||||
PinnedMessagesBannerState.Hidden -> Unit
|
||||
is PinnedMessagesBannerState.Loading -> {
|
||||
PinnedMessagesBannerRow(
|
||||
state = state,
|
||||
onViewAllClick = onViewAllClick,
|
||||
modifier = Modifier.clickable(onClick = { }),
|
||||
)
|
||||
}
|
||||
is PinnedMessagesBannerState.Loaded -> {
|
||||
fun onClick() {
|
||||
onClick(state.currentPinnedMessage.eventId)
|
||||
state.eventSink(PinnedMessagesBannerEvents.MoveToNextPinned)
|
||||
}
|
||||
|
||||
PinnedMessagesBannerRow(
|
||||
state = state,
|
||||
onViewAllClick = onViewAllClick,
|
||||
modifier = Modifier.clickable(onClick = ::onClick),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PinnedMessagesBannerRow(
|
||||
state: PinnedMessagesBannerState,
|
||||
onViewAllClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val borderColor = ElementTheme.colors.pinnedMessageBannerBorder
|
||||
Row(
|
||||
modifier = modifier
|
||||
.background(color = ElementTheme.colors.bgCanvasDefault)
|
||||
.fillMaxWidth()
|
||||
.drawBehind {
|
||||
val strokeWidth = 0.5.dp.toPx()
|
||||
val y = size.height - strokeWidth / 2
|
||||
drawLine(
|
||||
borderColor,
|
||||
Offset(0f, y),
|
||||
Offset(size.width, y),
|
||||
strokeWidth
|
||||
)
|
||||
drawLine(
|
||||
borderColor,
|
||||
Offset(0f, 0f),
|
||||
Offset(size.width, 0f),
|
||||
strokeWidth
|
||||
)
|
||||
}
|
||||
.shadow(elevation = 5.dp, spotColor = Color.Transparent)
|
||||
.heightIn(min = 64.dp)
|
||||
.clickable {
|
||||
onClick(state.currentPinnedMessage.eventId)
|
||||
state.eventSink(PinnedMessagesBannerEvents.MoveToNextPinned)
|
||||
},
|
||||
.background(color = ElementTheme.colors.bgCanvasDefault)
|
||||
.fillMaxWidth()
|
||||
.drawBorder(borderColor)
|
||||
.heightIn(min = 64.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = spacedBy(10.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
PinIndicators(
|
||||
pinIndex = state.currentPinnedMessageIndex,
|
||||
pinsCount = state.pinnedMessagesCount,
|
||||
pinIndex = state.currentPinnedMessageIndex(),
|
||||
pinsCount = state.pinnedMessagesCount(),
|
||||
modifier = Modifier.heightIn(max = 40.dp)
|
||||
)
|
||||
Icon(
|
||||
@@ -116,15 +126,56 @@ fun PinnedMessagesBannerView(
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
PinnedMessageItem(
|
||||
index = state.currentPinnedMessageIndex,
|
||||
totalCount = state.pinnedMessagesCount,
|
||||
message = state.currentPinnedMessage.formatted,
|
||||
index = state.currentPinnedMessageIndex(),
|
||||
totalCount = state.pinnedMessagesCount(),
|
||||
message = state.formattedMessage(),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
TextButton(text = stringResource(id = CommonStrings.screen_room_pinned_banner_view_all_button_title), onClick = onViewAllClick)
|
||||
ViewAllButton(state, onViewAllClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ViewAllButton(
|
||||
state: PinnedMessagesBannerState,
|
||||
onViewAllClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
val text = if (state is PinnedMessagesBannerState.Loaded) {
|
||||
stringResource(id = CommonStrings.screen_room_pinned_banner_view_all_button_title)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
TextButton(
|
||||
text = text,
|
||||
showProgress = state is PinnedMessagesBannerState.Loading,
|
||||
onClick = onViewAllClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Modifier.drawBorder(borderColor: Color): Modifier {
|
||||
return this
|
||||
.drawBehind {
|
||||
val strokeWidth = 0.5.dp.toPx()
|
||||
val y = size.height - strokeWidth / 2
|
||||
drawLine(
|
||||
borderColor,
|
||||
Offset(0f, y),
|
||||
Offset(size.width, y),
|
||||
strokeWidth
|
||||
)
|
||||
drawLine(
|
||||
borderColor,
|
||||
Offset(0f, 0f),
|
||||
Offset(size.width, 0f),
|
||||
strokeWidth
|
||||
)
|
||||
}
|
||||
.shadow(elevation = 5.dp, spotColor = Color.Transparent)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PinIndicators(
|
||||
pinIndex: Int,
|
||||
@@ -157,15 +208,15 @@ private fun PinIndicators(
|
||||
items(pinsCount) { index ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(2.dp)
|
||||
.height(indicatorHeight.dp)
|
||||
.background(
|
||||
color = if (index == pinIndex) {
|
||||
ElementTheme.colors.iconAccentPrimary
|
||||
} else {
|
||||
ElementTheme.colors.pinnedMessageBannerIndicator
|
||||
}
|
||||
)
|
||||
.width(2.dp)
|
||||
.height(indicatorHeight.dp)
|
||||
.background(
|
||||
color = if (index == pinIndex) {
|
||||
ElementTheme.colors.iconAccentPrimary
|
||||
} else {
|
||||
ElementTheme.colors.pinnedMessageBannerIndicator
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -175,7 +226,7 @@ private fun PinIndicators(
|
||||
private fun PinnedMessageItem(
|
||||
index: Int,
|
||||
totalCount: Int,
|
||||
message: AnnotatedString,
|
||||
message: AnnotatedString?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val countMessage = stringResource(id = CommonStrings.screen_room_pinned_banner_indicator, index + 1, totalCount)
|
||||
@@ -193,13 +244,15 @@ private fun PinnedMessageItem(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = message,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
if (message != null) {
|
||||
Text(
|
||||
text = message,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
||||
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory
|
||||
import io.element.android.features.messages.impl.messagecomposer.DefaultMessageComposerContext
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter
|
||||
import io.element.android.features.messages.impl.pinned.banner.aPinnedMessagesBannerState
|
||||
import io.element.android.features.messages.impl.pinned.banner.aLoadedPinnedMessagesBannerState
|
||||
import io.element.android.features.messages.impl.textcomposer.TestRichTextEditorStateFactory
|
||||
import io.element.android.features.messages.impl.timeline.TimelineController
|
||||
import io.element.android.features.messages.impl.timeline.TimelineItemIndexer
|
||||
@@ -1072,7 +1072,7 @@ class MessagesPresenterTest {
|
||||
customReactionPresenter = customReactionPresenter,
|
||||
reactionSummaryPresenter = reactionSummaryPresenter,
|
||||
readReceiptBottomSheetPresenter = readReceiptBottomSheetPresenter,
|
||||
pinnedMessagesBannerPresenter = { aPinnedMessagesBannerState() },
|
||||
pinnedMessagesBannerPresenter = { aLoadedPinnedMessagesBannerState() },
|
||||
networkMonitor = FakeNetworkMonitor(),
|
||||
snackbarDispatcher = SnackbarDispatcher(),
|
||||
navigator = navigator,
|
||||
|
||||
@@ -293,6 +293,7 @@ Reason: %1$s."</string>
|
||||
<string name="screen_room_member_details_unblock_user">"Unblock user"</string>
|
||||
<string name="screen_room_pinned_banner_indicator">"%1$s of %2$s"</string>
|
||||
<string name="screen_room_pinned_banner_indicator_description">"%1$s Pinned messages"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Loading message…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"View All"</string>
|
||||
<string name="screen_room_title">"Chat"</string>
|
||||
<string name="screen_share_location_title">"Share location"</string>
|
||||
|
||||
Reference in New Issue
Block a user