@@ -11,8 +11,8 @@ import androidx.camera.core.CameraInfo
1111import androidx.camera.core.FocusMeteringAction
1212import androidx.camera.core.MeteringPoint
1313import androidx.compose.ui.geometry.Offset
14+ import com.getcode.ui.utils.AnimationUtils
1415import java.util.concurrent.TimeUnit
15- import kotlin.math.pow
1616
1717internal class CameraGestureController (
1818 context : Context ,
@@ -25,9 +25,24 @@ internal class CameraGestureController(
2525 private val handler = Handler (Looper .getMainLooper())
2626 private var shouldIgnoreScroll = false
2727 private var resetIgnore: Runnable ? = null
28- private var initialZoomLevel = 0f
28+ private var initialZoomRatio = 0f
29+ private var initialZoomLevel = - 1f
2930 private var accumulatedDelta = 0f
3031
32+ private val maxZoom: Float
33+ get() = maxZoomOrNull ? : 1f
34+ private val minZoom: Float
35+ get() = minZoomOrNull ? : 1f
36+
37+ private val maxZoomOrNull: Float?
38+ get() = cameraInfo.zoomState.value?.maxZoomRatio
39+
40+ private val minZoomOrNull: Float?
41+ get() = cameraInfo.zoomState.value?.minZoomRatio
42+
43+ private val currentZoom: Float
44+ get() = cameraInfo.zoomState.value?.zoomRatio ? : 1f
45+
3146 // Pinch-to-zoom gesture detector
3247 private val scaleGestureDetector = ScaleGestureDetector (
3348 context,
@@ -39,14 +54,13 @@ internal class CameraGestureController(
3954 }
4055
4156 override fun onScale (detector : ScaleGestureDetector ): Boolean {
42- val currentZoomRatio = cameraInfo.zoomState.value?.zoomRatio ? : 1f
4357 val delta = detector.scaleFactor
44- val newZoomRatio = currentZoomRatio * delta
58+ val newZoomRatio = currentZoom * delta
4559
4660 // Clamp the new zoom ratio between the minimum and maximum zoom ratio
4761 val clampedZoomRatio = newZoomRatio.coerceIn(
48- cameraInfo.zoomState.value?.minZoomRatio ? : 1f ,
49- cameraInfo.zoomState.value?.maxZoomRatio ? : currentZoomRatio
62+ minZoom ,
63+ maxZoomOrNull ? : currentZoom
5064 )
5165
5266 // Apply the zoom to the camera control
@@ -55,7 +69,7 @@ internal class CameraGestureController(
5569 }
5670
5771 override fun onScaleEnd (detector : ScaleGestureDetector ) {
58- initialZoomLevel = cameraInfo.zoomState.value?.zoomRatio ? : 1f
72+ initialZoomRatio = currentZoom
5973 resetIgnore = Runnable { shouldIgnoreScroll = false }
6074 resetIgnore?.let { handler.postDelayed(it, 500 ) }
6175 }
@@ -66,7 +80,7 @@ internal class CameraGestureController(
6680 context,
6781 object : GestureDetector .OnGestureListener {
6882 override fun onDown (e : MotionEvent ): Boolean {
69- initialZoomLevel = cameraInfo.zoomState.value?.zoomRatio ? : 1f
83+ initialZoomRatio = currentZoom
7084 accumulatedDelta = 0f
7185 return true
7286 }
@@ -94,18 +108,15 @@ internal class CameraGestureController(
94108 accumulatedDelta - distanceY * 0.5f
95109 }
96110
97- val zoomDelta = ease(
111+ val zoomDelta = AnimationUtils . ease(
98112 value = accumulatedDelta,
99113 fromRange = 0f .. 250f ,
100114 toRange = 0f .. 10f ,
101115 easeIn = true ,
102116 easeOut = false
103117 )
104118
105- val maxZoom = cameraInfo.zoomState.value?.maxZoomRatio ? : 1f
106- val minZoom = cameraInfo.zoomState.value?.minZoomRatio ? : 1f
107-
108- val newZoom = (initialZoomLevel + zoomDelta).coerceIn(minZoom, maxZoom)
119+ val newZoom = (initialZoomRatio + zoomDelta).coerceIn(minZoom, maxZoom)
109120 cameraControl.setZoomRatio(newZoom)
110121 }
111122 return true
@@ -126,12 +137,16 @@ internal class CameraGestureController(
126137
127138 fun onTouchEvent (event : MotionEvent ) {
128139 if (gesturesEnabled) {
140+ if (initialZoomLevel == - 1f ) {
141+ initialZoomLevel = cameraInfo.zoomState.value?.linearZoom ? : 0f
142+ }
143+
129144 scaleGestureDetector.onTouchEvent(event)
130145 gestureDetector.onTouchEvent(event)
131146
132147 if (event.action == MotionEvent .ACTION_UP ) {
133148 animateZoomReset(cameraInfo, cameraControl)
134- initialZoomLevel = cameraInfo.zoomState.value?.zoomRatio ? : 1f
149+ initialZoomRatio = currentZoom
135150 }
136151 }
137152 }
@@ -149,7 +164,7 @@ internal class CameraGestureController(
149164 override fun run () {
150165 if (currentStep < maxSteps) {
151166 val newZoomLevel = currentZoomLevel - (decrement * currentStep)
152- cameraControl?.setLinearZoom(newZoomLevel.coerceIn(0f , 1f ))
167+ cameraControl?.setLinearZoom(newZoomLevel.coerceIn(initialZoomLevel , 1f ))
153168 currentStep++
154169 handler.postDelayed(this , frameInterval)
155170 } else {
@@ -158,30 +173,4 @@ internal class CameraGestureController(
158173 }
159174 })
160175 }
161-
162- private fun ease (
163- value : Float ,
164- fromRange : ClosedFloatingPointRange <Float >,
165- toRange : ClosedFloatingPointRange <Float >,
166- easeIn : Boolean ,
167- easeOut : Boolean
168- ): Float {
169- val normalizedValue = (value - fromRange.start) / (fromRange.endInclusive - fromRange.start)
170-
171- val easedValue: Float = if (easeIn && easeOut) {
172- if (normalizedValue < 0.5f ) {
173- 4 * normalizedValue * normalizedValue * normalizedValue
174- } else {
175- 1 - (- 2 * normalizedValue + 2 ).toDouble().pow(3.0 ).toFloat() / 2
176- }
177- } else if (easeIn) {
178- normalizedValue * normalizedValue * normalizedValue
179- } else if (easeOut) {
180- 1 - (1 - normalizedValue).toDouble().pow(3.0 ).toFloat()
181- } else {
182- normalizedValue
183- }
184-
185- return easedValue * (toRange.endInclusive - toRange.start) + toRange.start
186- }
187176}
0 commit comments