improved image views
This commit is contained in:
parent
1c6a80c43b
commit
44a83a17dd
@ -6,8 +6,11 @@ import androidx.compose.foundation.gestures.detectDragGestures
|
||||
import androidx.compose.foundation.gestures.rememberTransformableState
|
||||
import androidx.compose.foundation.gestures.transformable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
@ -35,7 +38,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
@ -66,6 +68,8 @@ internal fun ImageViewer(
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
val imageBackgroundColor = readerImageBackgroundColor()
|
||||
val imageAspectRatio = image.bitmap.width.toFloat() / image.bitmap.height.toFloat()
|
||||
|
||||
fun setScale(next: Float) {
|
||||
scale = next.coerceIn(MinImageScale, MaxImageScale)
|
||||
@ -133,11 +137,11 @@ internal fun ImageViewer(
|
||||
}
|
||||
},
|
||||
) { padding ->
|
||||
Box(
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
.background(Color.Black)
|
||||
.background(readerBackground())
|
||||
.focusRequester(focusRequester)
|
||||
.onPreviewKeyEvent { event ->
|
||||
if (event.type != KeyEventType.KeyDown) return@onPreviewKeyEvent false
|
||||
@ -171,19 +175,28 @@ internal fun ImageViewer(
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Image(
|
||||
bitmap = image.bitmap,
|
||||
contentDescription = image.title,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
val imageModifier = if (maxWidth / maxHeight > imageAspectRatio) {
|
||||
Modifier.fillMaxHeight().aspectRatio(imageAspectRatio)
|
||||
} else {
|
||||
Modifier.fillMaxWidth().aspectRatio(imageAspectRatio)
|
||||
}
|
||||
Box(
|
||||
modifier = imageModifier
|
||||
.graphicsLayer {
|
||||
scaleX = scale
|
||||
scaleY = scale
|
||||
translationX = offset.x
|
||||
translationY = offset.y
|
||||
},
|
||||
}
|
||||
.background(imageBackgroundColor),
|
||||
) {
|
||||
Image(
|
||||
bitmap = image.bitmap,
|
||||
contentDescription = image.title,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.Fit,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
@ -16,6 +17,7 @@ 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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -47,6 +49,7 @@ import androidx.compose.ui.input.pointer.PointerEventPass
|
||||
import androidx.compose.ui.input.pointer.PointerType
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@ -368,6 +371,7 @@ internal fun CoverAndTitle(book: Fb2Book, onImageOpen: (ViewedBookImage) -> Unit
|
||||
image = book.coverImages.firstOrNull() ?: book.bodyImages.firstOrNull(),
|
||||
modifier = Modifier.width(112.dp).aspectRatio(0.68f),
|
||||
contentScale = ContentScale.Crop,
|
||||
fitBackgroundToBitmapBounds = false,
|
||||
onOpen = onImageOpen,
|
||||
)
|
||||
Column(verticalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.weight(1f)) {
|
||||
@ -564,6 +568,7 @@ private fun BookImage(
|
||||
image: Fb2ImageRef?,
|
||||
modifier: Modifier = Modifier,
|
||||
contentScale: ContentScale = ContentScale.Fit,
|
||||
fitBackgroundToBitmapBounds: Boolean = true,
|
||||
onOpen: (ViewedBookImage) -> Unit = {},
|
||||
) {
|
||||
val binary = remember(book, image) {
|
||||
@ -573,10 +578,12 @@ private fun BookImage(
|
||||
binary?.let { decodeBookImage(it) }
|
||||
}
|
||||
val imageTitle = image?.alt?.ifBlank { null } ?: book.title
|
||||
Box(
|
||||
val imageBackgroundColor = readerImageBackgroundColor()
|
||||
val density = LocalDensity.current
|
||||
BoxWithConstraints(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.then(
|
||||
if (bitmap != null && binary != null) {
|
||||
Modifier.clickable {
|
||||
@ -596,12 +603,23 @@ private fun BookImage(
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
if (bitmap != null) {
|
||||
val imageAspectRatio = bitmap.width.toFloat() / bitmap.height.coerceAtLeast(1).toFloat()
|
||||
val imageModifier = if (fitBackgroundToBitmapBounds) {
|
||||
val bitmapWidth = with(density) { bitmap.width.toDp() }
|
||||
Modifier
|
||||
.width(if (bitmapWidth < maxWidth) bitmapWidth else maxWidth)
|
||||
.aspectRatio(imageAspectRatio)
|
||||
} else {
|
||||
Modifier.fillMaxSize()
|
||||
}
|
||||
Box(imageModifier.background(imageBackgroundColor)) {
|
||||
Image(
|
||||
bitmap = bitmap,
|
||||
contentDescription = imageTitle,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = contentScale,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(strings.noImage, style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.outline)
|
||||
}
|
||||
|
||||
@ -22,7 +22,9 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.lerp
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlin.math.roundToInt
|
||||
@ -107,6 +109,16 @@ internal fun themedTopAppBarColors(): TopAppBarColors =
|
||||
@Composable
|
||||
internal fun readerBackground(): Brush = SolidColor(MaterialTheme.colorScheme.background)
|
||||
|
||||
@Composable
|
||||
internal fun readerImageBackgroundColor(): Color {
|
||||
val surface = MaterialTheme.colorScheme.surface
|
||||
return if (surface.isVisuallyDark()) lerp(surface, Color.White, 0.5f) else surface
|
||||
}
|
||||
|
||||
private fun Color.isVisuallyDark(): Boolean {
|
||||
val luminance = 0.2126f * red + 0.7152f * green + 0.0722f * blue
|
||||
return luminance < 0.5f
|
||||
}
|
||||
|
||||
internal fun Int.formatCompact(): String =
|
||||
if (this >= 10_000) "${(this / 1000.0).roundToInt()}k" else toString()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user