|
|
|
|
@ -2,7 +2,11 @@ package com.utun.chat.ui.components
|
|
|
|
|
|
|
|
|
|
import android.graphics.Bitmap |
|
|
|
|
import androidx.compose.foundation.Image |
|
|
|
|
import androidx.compose.foundation.gestures.detectTransformGestures |
|
|
|
|
import androidx.compose.foundation.gestures.awaitEachGesture |
|
|
|
|
import androidx.compose.foundation.gestures.awaitFirstDown |
|
|
|
|
import androidx.compose.foundation.gestures.calculateCentroid |
|
|
|
|
import androidx.compose.foundation.gestures.calculatePan |
|
|
|
|
import androidx.compose.foundation.gestures.calculateZoom |
|
|
|
|
import androidx.compose.foundation.layout.Box |
|
|
|
|
import androidx.compose.foundation.layout.BoxWithConstraints |
|
|
|
|
import androidx.compose.foundation.layout.fillMaxSize |
|
|
|
|
@ -12,6 +16,7 @@ import androidx.compose.ui.geometry.Offset
|
|
|
|
|
import androidx.compose.ui.graphics.asImageBitmap |
|
|
|
|
import androidx.compose.ui.graphics.graphicsLayer |
|
|
|
|
import androidx.compose.ui.input.pointer.pointerInput |
|
|
|
|
import androidx.compose.ui.input.pointer.positionChanged |
|
|
|
|
import androidx.compose.ui.layout.ContentScale |
|
|
|
|
import androidx.compose.ui.platform.LocalDensity |
|
|
|
|
|
|
|
|
|
@ -31,6 +36,7 @@ fun ZoomableImage(bitmap: Bitmap, modifier: Modifier = Modifier, contentScale: C
|
|
|
|
|
onSwipe: ((Int) -> Unit)? = null) { |
|
|
|
|
var zoomScale by remember(bitmap) { mutableStateOf(1f) } |
|
|
|
|
var zoomOffset by remember(bitmap) { mutableStateOf(Offset.Zero) } |
|
|
|
|
val navigate by rememberUpdatedState(onSwipe) |
|
|
|
|
|
|
|
|
|
BoxWithConstraints(modifier) { |
|
|
|
|
val density = LocalDensity.current |
|
|
|
|
@ -60,13 +66,19 @@ fun ZoomableImage(bitmap: Bitmap, modifier: Modifier = Modifier, contentScale: C
|
|
|
|
|
Box( |
|
|
|
|
modifier = Modifier |
|
|
|
|
.fillMaxSize() |
|
|
|
|
.pointerInput(bitmap,cW,cH,onSwipe) { |
|
|
|
|
var swipe=0f |
|
|
|
|
detectTransformGestures { centroid, pan, zoom, _ -> |
|
|
|
|
if (onSwipe!=null && zoomScale==1f && zoom==1f && kotlin.math.abs(pan.x)>kotlin.math.abs(pan.y)) { |
|
|
|
|
.pointerInput(bitmap,cW,cH) { |
|
|
|
|
awaitEachGesture { |
|
|
|
|
awaitFirstDown(requireUnconsumed=false) |
|
|
|
|
var swipe=0f; var swiped=false; var canSwipe=zoomScale==1f |
|
|
|
|
do { |
|
|
|
|
val event=awaitPointerEvent() |
|
|
|
|
val centroid=event.calculateCentroid(useCurrent=false) |
|
|
|
|
val pan=event.calculatePan(); val zoom=event.calculateZoom() |
|
|
|
|
if (event.changes.count { it.pressed }!=1 || zoom!=1f) canSwipe=false |
|
|
|
|
if (canSwipe && !swiped && navigate!=null && kotlin.math.abs(pan.x)>kotlin.math.abs(pan.y)) { |
|
|
|
|
swipe+=pan.x |
|
|
|
|
if (kotlin.math.abs(swipe)>96*density.density) { onSwipe(if (swipe<0) 1 else -1); swipe=0f } |
|
|
|
|
} else swipe=0f |
|
|
|
|
if (kotlin.math.abs(swipe)>96*density.density) { navigate?.invoke(if (swipe<0) 1 else -1); swiped=true } |
|
|
|
|
} |
|
|
|
|
val old = zoomScale |
|
|
|
|
val new = (zoomScale * zoom).coerceIn(1f, MAX_ZOOM) |
|
|
|
|
val z = new / old |
|
|
|
|
@ -77,6 +89,8 @@ fun ZoomableImage(bitmap: Bitmap, modifier: Modifier = Modifier, contentScale: C
|
|
|
|
|
) |
|
|
|
|
zoomScale = new |
|
|
|
|
zoomOffset = clampOffset(new, raw, cW, cH, iw, ih) |
|
|
|
|
if (zoom!=1f || pan!=Offset.Zero) event.changes.forEach { if (it.positionChanged()) it.consume() } |
|
|
|
|
} while (event.changes.any { it.pressed }) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
|