android: upgrade fullscreen media viewer header and gallery
Some checks failed
CI / test (push) Failing after 2m14s

This commit is contained in:
Codex
2026-03-09 14:38:27 +03:00
parent c947d96748
commit d09300311f
3 changed files with 78 additions and 12 deletions

View File

@@ -275,3 +275,9 @@
- Added file-list style attachment rows (icon + filename + type/size metadata).
- Upgraded non-voice audio attachment player with play/pause, progress bar, and current/total duration labels.
- Updated Telegram UI batch-2 checklist media-bubble items.
### Step 46 - Media viewer / header and gallery navigation
- Upgraded chat image viewer to use global image gallery state (`index / total`) instead of a single URL.
- Added fullscreen viewer header with close, index, share placeholder, and delete placeholder actions.
- Added image navigation controls (`Prev`/`Next`) for gallery traversal.
- Updated Telegram UI batch-2 checklist for fullscreen media header support.

View File

@@ -123,7 +123,15 @@ fun ChatScreen(
onLoadMore: () -> Unit,
onPickMedia: () -> Unit,
) {
var viewerImageUrl by remember { mutableStateOf<String?>(null) }
val allImageUrls = remember(state.messages) {
state.messages
.flatMap { message -> message.attachments }
.map { it.fileUrl to it.fileType.lowercase() }
.filter { (_, type) -> type.startsWith("image/") }
.map { (url, _) -> url }
.distinct()
}
var viewerImageIndex by remember { mutableStateOf<Int?>(null) }
var dismissedPinnedMessageId by remember { mutableStateOf<Long?>(null) }
var actionMenuMessage by remember { mutableStateOf<MessageItem?>(null) }
Column(
@@ -241,7 +249,10 @@ fun ChatScreen(
message = message,
isSelected = isSelected,
reactions = state.reactionByMessageId[message.id].orEmpty(),
onAttachmentImageClick = { imageUrl -> viewerImageUrl = imageUrl },
onAttachmentImageClick = { imageUrl ->
val idx = allImageUrls.indexOf(imageUrl)
viewerImageIndex = if (idx >= 0) idx else null
},
onClick = {
actionMenuMessage = null
if (state.actionState.mode == MessageSelectionMode.MULTI) {
@@ -495,22 +506,71 @@ fun ChatScreen(
)
}
if (viewerImageUrl != null) {
if (viewerImageIndex != null) {
val currentIndex = viewerImageIndex ?: 0
val currentUrl = allImageUrls.getOrNull(currentIndex)
Surface(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.scrim.copy(alpha = 0.7f))
.clickable { viewerImageUrl = null },
.clickable { },
) {
Box(contentAlignment = Alignment.Center) {
AsyncImage(
model = viewerImageUrl,
contentDescription = "Attachment",
Column(modifier = Modifier.fillMaxSize()) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
contentScale = ContentScale.Fit,
)
.padding(horizontal = 12.dp, vertical = 10.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Button(onClick = { viewerImageIndex = null }) { Text("") }
Text(
text = "${currentIndex + 1}/${allImageUrls.size.coerceAtLeast(1)}",
style = MaterialTheme.typography.titleSmall,
)
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
Button(onClick = {}, enabled = false) { Text("") }
Button(onClick = {}, enabled = false) { Text("🗑") }
}
}
Box(
modifier = Modifier.weight(1f),
contentAlignment = Alignment.Center,
) {
if (currentUrl != null) {
AsyncImage(
model = currentUrl,
contentDescription = "Attachment",
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
contentScale = ContentScale.Fit,
)
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 10.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Button(
onClick = {
viewerImageIndex = if (allImageUrls.isEmpty()) null else {
(currentIndex - 1).coerceAtLeast(0)
}
},
enabled = currentIndex > 0,
) { Text("Prev") }
Button(
onClick = {
viewerImageIndex = if (allImageUrls.isEmpty()) null else {
(currentIndex + 1).coerceAtMost(allImageUrls.lastIndex)
}
},
enabled = currentIndex < allImageUrls.lastIndex,
) { Text("Next") }
}
}
}
}

View File

@@ -35,7 +35,7 @@
- [ ] Метаданные поста/канала (просмотры/время/reaction strip) у медиа-сообщений.
## P1 — Fullscreen Media Viewer
- [ ] Fullscreen header: close + index ("1") + share + delete.
- [x] Fullscreen header: close + index ("1") + share + delete.
- [ ] Поддержка reaction overlay в viewer (как на скрине).
- [ ] Свайп между медиа (gallery mode), если в сообщении несколько вложений.