diff --git a/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt b/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt index 8320091..6de9d1a 100755 --- a/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt +++ b/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt @@ -24,6 +24,7 @@ import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient import android.widget.TextView +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -38,7 +39,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -170,7 +170,7 @@ private val headingMetrics = mapOf( "h6" to TextBlockMetrics(22f, 8f, 10f), ) -@OptIn(ExperimentalCoroutinesApi::class) +@OptIn(ExperimentalCoroutinesApi::class, ExperimentalFoundationApi::class) @Composable fun Room(modifier: Modifier = Modifier, rid: String) { val roomId = remember(rid) { RoomId(rid) } @@ -196,9 +196,23 @@ fun Room(modifier: Modifier = Modifier, rid: String) { Column(modifier) { var message by remember { mutableStateOf("") } - LazyColumn(Modifier.weight(1f), state = listState, reverseLayout = true) { - items(timelineItems, key = { it.key }) { item -> - TimelineItem(item) + LaunchedEffect(timelineItems.size) { + if (timelineItems.isNotEmpty()) { + listState.scrollToItem(timelineItems.lastIndex) + } + } + + LazyColumn(Modifier.weight(1f), state = listState) { + for (timelineItem in timelineItems) { + when (timelineItem) { + is DateDividerItem -> stickyHeader(key = timelineItem.key) { + DateDivider(timelineItem) + } + + else -> item(key = timelineItem.key) { + TimelineItem(timelineItem) + } + } } if (timelineItems.isEmpty()) { @@ -307,12 +321,12 @@ private fun buildTimelineItems( val previousMessage = lastMessageIndex ?.let { items.getOrNull(it) as? MessageTimelineItem } val groupedWithPrevious = previousMessage != null && - previousMessage.senderId != null && - previousMessage.senderId == senderId && - previousMessage.isOwn == isOwn && - previousMessage.timestampMs != null && - timestampMs != null && - timestampMs - previousMessage.timestampMs <= MESSAGE_GROUP_WINDOW_MS + previousMessage.senderId != null && + previousMessage.senderId == senderId && + previousMessage.isOwn == isOwn && + previousMessage.timestampMs != null && + timestampMs != null && + timestampMs - previousMessage.timestampMs <= MESSAGE_GROUP_WINDOW_MS if (groupedWithPrevious) { items[lastMessageIndex] = previousMessage.copy(showTimestamp = false) @@ -351,7 +365,7 @@ private fun buildTimelineItems( } } - return items.asReversed() + return items } @Composable @@ -365,15 +379,25 @@ private fun TimelineItem(item: TimelineUiItem) { @Composable private fun DateDivider(item: DateDividerItem) { - Text( - text = item.label, + Box( modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp), - textAlign = TextAlign.Center, - style = MaterialTheme.typography.labelSmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) + contentAlignment = Alignment.Center, + ) { + Text( + text = item.label, + modifier = Modifier + .background( + color = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = 0.8f), + shape = RoundedCornerShape(50), + ) + .padding(horizontal = 12.dp, vertical = 4.dp), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } } @Composable @@ -946,8 +970,8 @@ private fun ComplexHtmlRenderer( val resolvedHeightPx = rawHeightPx.coerceAtLeast(1) val currentHeightPx = measuredHeightPx ?: estimatedHeightPx val shouldUpdate = measuredHeightPx == null || - resolvedHeightPx > currentHeightPx || - abs(resolvedHeightPx - currentHeightPx) > updateThresholdPx + resolvedHeightPx > currentHeightPx || + abs(resolvedHeightPx - currentHeightPx) > updateThresholdPx if (shouldUpdate) { complexHtmlHeightCache[cacheKey] = resolvedHeightPx @@ -1003,7 +1027,7 @@ private fun ComplexHtmlRenderer( val currentView = view ?: return currentView.post { val fallbackHeightPx = (currentView.contentHeight * - currentView.resources.displayMetrics.density).roundToInt() + currentView.resources.displayMetrics.density).roundToInt() if (fallbackHeightPx > 0) { onHeightMeasured(fallbackHeightPx) }