feat: open app screenshots fullscreen via ZoomableContentView

ScreenshotsStrip now renders each screenshot through ZoomableContentView,
so tapping one opens the standard fullscreen zoomable viewer with paging
across all of the app's screenshots. Tiles keep a fixed height and take
their width from the image's cached aspect ratio (portrait fallback
before first load).

https://claude.ai/code/session_01RJSke6d4dpSZgdtXAmGMmp
This commit is contained in:
Claude
2026-06-12 19:31:31 +00:00
parent 8c7430038d
commit bb43fd97b8
2 changed files with 34 additions and 13 deletions
@@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -60,11 +61,14 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil3.compose.AsyncImage
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent
import com.vitorpamplona.amethyst.ui.components.ClickableTextPrimary
import com.vitorpamplona.amethyst.ui.components.ZoomableContentView
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.note.LinkIcon
@@ -87,6 +91,7 @@ import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.SoftwareR
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.asSoftwareRelease
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.isNip82SoftwareRelease
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -168,7 +173,7 @@ fun RenderSoftwareApplication(
if (images.isNotEmpty()) {
Spacer(StdVertSpacer)
ScreenshotsStrip(images, imageHeight = 200.dp)
ScreenshotsStrip(images, accountViewModel, imageHeight = 200.dp)
}
}
@@ -327,26 +332,42 @@ fun TopicChipFlow(
@Composable
fun ScreenshotsStrip(
images: List<String>,
accountViewModel: AccountViewModel,
contentPadding: PaddingValues = PaddingValues(0.dp),
imageHeight: Dp = 180.dp,
) {
if (images.isEmpty()) return
val mediaContents =
remember(images) {
images.map { MediaUrlImage(url = it) }.toImmutableList()
}
LazyRow(
horizontalArrangement = Arrangement.spacedBy(6.dp),
contentPadding = contentPadding,
modifier = Modifier.height(imageHeight),
) {
items(images) { imageUrl ->
AsyncImage(
model = imageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier =
Modifier
.height(imageHeight)
.clip(RoundedCornerShape(8.dp))
.border(1.dp, MaterialTheme.colorScheme.subtleBorder, RoundedCornerShape(8.dp)),
)
items(mediaContents) { content ->
// Fixed-height tile whose width follows the image's aspect ratio
// once it is known; assumes a portrait phone screenshot before the
// first load fills the ratio cache.
val ratio = MediaAspectRatioCache.get(content.url) ?: (9f / 16f)
Box(
Modifier
.height(imageHeight)
.aspectRatio(ratio)
.clip(RoundedCornerShape(8.dp))
.border(1.dp, MaterialTheme.colorScheme.subtleBorder, RoundedCornerShape(8.dp)),
) {
ZoomableContentView(
content = content,
images = mediaContents,
roundedCorner = false,
contentScale = ContentScale.Crop,
accountViewModel = accountViewModel,
)
}
}
}
}
@@ -216,7 +216,7 @@ private fun SoftwareAppDetailBody(
if (images.isNotEmpty()) {
item(key = "screenshots") {
Spacer(Modifier.height(12.dp))
ScreenshotsStrip(images, contentPadding = PaddingValues(horizontal = 12.dp))
ScreenshotsStrip(images, accountViewModel, contentPadding = PaddingValues(horizontal = 12.dp))
}
}