Pdf: improve rendering with zoom and spaces between pages

This commit is contained in:
ganfra 2023-05-31 23:48:23 +02:00
parent dfacb42d76
commit e754d17c13

View file

@ -21,6 +21,7 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -48,10 +49,10 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.MimeTypes
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.AspectRatioFrameLayout
@ -60,14 +61,19 @@ import io.element.android.features.messages.impl.media.local.exoplayer.ExoPlayer
import io.element.android.features.messages.impl.media.local.pdf.ParcelFileDescriptorFactory import io.element.android.features.messages.impl.media.local.pdf.ParcelFileDescriptorFactory
import io.element.android.features.messages.impl.media.local.pdf.PdfPage import io.element.android.features.messages.impl.media.local.pdf.PdfPage
import io.element.android.features.messages.impl.media.local.pdf.PdfRendererManager import io.element.android.features.messages.impl.media.local.pdf.PdfRendererManager
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeImage
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo
import io.element.android.libraries.designsystem.R import io.element.android.libraries.designsystem.R
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import me.saket.telephoto.zoomable.ZoomSpec import me.saket.telephoto.zoomable.ZoomSpec
import me.saket.telephoto.zoomable.ZoomableState
import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage
import me.saket.telephoto.zoomable.rememberZoomableImageState import me.saket.telephoto.zoomable.rememberZoomableImageState
import me.saket.telephoto.zoomable.rememberZoomableState import me.saket.telephoto.zoomable.rememberZoomableState
import me.saket.telephoto.zoomable.zoomable
@SuppressLint("UnsafeOptInUsageError") @SuppressLint("UnsafeOptInUsageError")
@Composable @Composable
@ -77,19 +83,28 @@ fun LocalMediaView(
mimeType: String? = localMedia?.mimeType, mimeType: String? = localMedia?.mimeType,
onReady: () -> Unit = {}, onReady: () -> Unit = {},
) { ) {
val zoomableState = rememberZoomableState(
zoomSpec = ZoomSpec(maxZoomFactor = 3f)
)
when { when {
MimeTypes.isImage(mimeType) -> MediaImageView( mimeType.isMimeTypeImage() -> MediaImageView(
localMedia = localMedia,
zoomableState = zoomableState,
onReady = onReady,
modifier = modifier
)
mimeType.isMimeTypeVideo() -> MediaVideoView(
localMedia = localMedia, localMedia = localMedia,
onReady = onReady, onReady = onReady,
modifier = modifier modifier = modifier
) )
MimeTypes.isVideo(mimeType) -> MediaVideoView( mimeType == MimeTypes.Pdf -> {
localMedia = localMedia, MediaPDFView(
onReady = onReady, localMedia = localMedia,
modifier = modifier zoomableState = zoomableState,
) onReady = onReady,
mimeType == io.element.android.libraries.core.mimetype.MimeTypes.Pdf -> { modifier = modifier
MediaPDFView(localMedia = localMedia, onReady = onReady, modifier = modifier) )
} }
else -> Unit else -> Unit
} }
@ -98,6 +113,7 @@ fun LocalMediaView(
@Composable @Composable
private fun MediaImageView( private fun MediaImageView(
localMedia: LocalMedia?, localMedia: LocalMedia?,
zoomableState: ZoomableState,
onReady: () -> Unit, onReady: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -108,9 +124,6 @@ private fun MediaImageView(
contentDescription = null, contentDescription = null,
) )
} else { } else {
val zoomableState = rememberZoomableState(
zoomSpec = ZoomSpec(maxZoomFactor = 3f)
)
val zoomableImageState = rememberZoomableImageState(zoomableState) val zoomableImageState = rememberZoomableImageState(zoomableState)
LaunchedEffect(zoomableImageState.isImageDisplayed) { LaunchedEffect(zoomableImageState.isImageDisplayed) {
if (zoomableImageState.isImageDisplayed) { if (zoomableImageState.isImageDisplayed) {
@ -186,15 +199,16 @@ fun MediaVideoView(
@Composable @Composable
fun MediaPDFView( fun MediaPDFView(
localMedia: LocalMedia?, localMedia: LocalMedia?,
zoomableState: ZoomableState,
onReady: () -> Unit, onReady: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
BoxWithConstraints( BoxWithConstraints(
modifier = modifier, modifier = modifier.zoomable(zoomableState),
contentAlignment = Alignment.TopCenter contentAlignment = Alignment.Center
) { ) {
val maxWidth = this.maxWidth.dpToPx() val maxWidth = this.maxWidth.dpToPx()
val lazyState = rememberLazyListState() val lazyListState = rememberLazyListState()
val context = LocalContext.current val context = LocalContext.current
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
var pdfRendererManager by remember { var pdfRendererManager by remember {
@ -214,7 +228,7 @@ fun MediaPDFView(
} }
pdfRendererManager?.run { pdfRendererManager?.run {
val pdfPages = pdfPages.collectAsState().value val pdfPages = pdfPages.collectAsState().value
PdfPagesView(pdfPages.toImmutableList(), lazyState) PdfPagesView(pdfPages.toImmutableList(), lazyListState)
} }
} }
} }
@ -227,7 +241,9 @@ private fun PdfPagesView(
) { ) {
LazyColumn( LazyColumn(
modifier = modifier.fillMaxSize(), modifier = modifier.fillMaxSize(),
state = lazyListState state = lazyListState,
verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically)
) { ) {
items(pdfPages.size) { index -> items(pdfPages.size) { index ->
val pdfPage = pdfPages[index] val pdfPage = pdfPages[index]