Skip to content

Commit b69de8b

Browse files
fix DynamicCropState
- update CropState updateProperties - fix DynamicCropState move, and gesture conflicts
1 parent bb75d4e commit b69de8b

File tree

2 files changed

+74
-52
lines changed

2 files changed

+74
-52
lines changed

cropper/src/main/java/com/smarttoolfactory/cropper/state/CropStateImpl.kt

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.smarttoolfactory.cropper.state
22

33
import androidx.compose.animation.core.Animatable
44
import androidx.compose.animation.core.VectorConverter
5+
import androidx.compose.animation.core.tween
56
import androidx.compose.ui.geometry.Offset
67
import androidx.compose.ui.geometry.Rect
78
import androidx.compose.ui.geometry.Size
@@ -44,7 +45,7 @@ abstract class CropState internal constructor(
4445
imageSize: IntSize,
4546
containerSize: IntSize,
4647
drawAreaSize: IntSize,
47-
aspectRatio: AspectRatio,
48+
private var aspectRatio: AspectRatio,
4849
maxZoom: Float,
4950
var fling: Boolean = true,
5051
zoomable: Boolean = true,
@@ -98,19 +99,30 @@ abstract class CropState internal constructor(
9899
rotatable = cropProperties.rotatable
99100

100101
// TODO Fix zoom reset
101-
// zoomMax = cropProperties.maxZoom
102+
val maxZoom = cropProperties.maxZoom
102103

103104
// Update overlay rectangle
104105
val aspectRatio = cropProperties.aspectRatio
105-
animateOverlayRectTo(
106-
getOverlayFromAspectRatio(
107-
containerSize.width.toFloat(),
108-
containerSize.height.toFloat(),
109-
drawAreaRect.size.width,
110-
drawAreaRect.size.height,
111-
aspectRatio
106+
107+
if(this.aspectRatio.value != aspectRatio.value || maxZoom != zoomMax) {
108+
109+
zoomMax = maxZoom
110+
animatableZoom.updateBounds(zoomMin, zoomMax)
111+
112+
val currentZoom = if(zoom>zoomMax) zoomMax else zoom
113+
114+
resetWithAnimation(zoom = currentZoom)
115+
116+
animateOverlayRectTo(
117+
getOverlayFromAspectRatio(
118+
containerSize.width.toFloat(),
119+
containerSize.height.toFloat(),
120+
drawAreaSize.width.toFloat(),
121+
drawAreaSize.height.toFloat(),
122+
aspectRatio
123+
)
112124
)
113-
)
125+
}
114126

115127
// Update image draw area
116128
updateImageDrawRectFromTransformation()
@@ -120,7 +132,10 @@ abstract class CropState internal constructor(
120132
* Animate overlay rectangle to target value
121133
*/
122134
suspend fun animateOverlayRectTo(rect: Rect) {
123-
animatableRectOverlay.animateTo(rect)
135+
animatableRectOverlay.animateTo(
136+
targetValue = rect,
137+
animationSpec = tween(500)
138+
)
124139
}
125140

126141
/**

cropper/src/main/java/com/smarttoolfactory/cropper/state/DynamicCropState.kt

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,22 @@ class DynamicCropState internal constructor(
113113
)
114114

115115
snapOverlayRectTo(newRect)
116+
// moveOverlayToBounds(change = change, newRect = newRect)
116117
}
117118

118119
override suspend fun onUp(change: PointerInputChange) = coroutineScope {
119-
120120
if (touchRegion != TouchRegion.None) {
121121
// Update overlay if it's out of Container bounds
122-
rectTemp = moveOverlayRectToBounds(rectBounds, overlayRect)
122+
rectTemp = calculateOverlayRectInBounds(rectBounds, overlayRect)
123123
animateOverlayRectTo(rectTemp)
124124

125125
// Update and animate pan, zoom and image draw area after overlay position is updated
126126
animateTransformationToOverlayBounds()
127127

128128
// Update image draw area after animating pan, zoom or rotation is completed
129129
updateImageDrawRectFromTransformation()
130-
131130
touchRegion = TouchRegion.None
132131
}
133-
134132
}
135133

136134
override suspend fun onGesture(
@@ -166,45 +164,53 @@ class DynamicCropState internal constructor(
166164
override suspend fun onGestureStart() = Unit
167165

168166
override suspend fun onGestureEnd(onBoundsCalculated: () -> Unit) {
169-
// Gesture end might be called after second tap and we don't want to fling
170-
// or animate back to valid bounds when doubled tapped
171-
if (!doubleTapped) {
172-
173-
if (fling && zoom > 1) {
174-
fling {
175-
// We get target value on start instead of updating bounds after
176-
// gesture has finished
177-
updateImageDrawRectFromTransformation()
167+
168+
if (touchRegion == TouchRegion.None) {
169+
170+
// Gesture end might be called after second tap and we don't want to fling
171+
// or animate back to valid bounds when doubled tapped
172+
if (!doubleTapped) {
173+
174+
if (fling && zoom > 1) {
175+
fling {
176+
// We get target value on start instead of updating bounds after
177+
// gesture has finished
178+
updateImageDrawRectFromTransformation()
179+
onBoundsCalculated()
180+
}
181+
} else {
178182
onBoundsCalculated()
179183
}
180-
} else {
181-
onBoundsCalculated()
182-
}
183184

184-
animateTransformationToOverlayBounds()
185+
animateTransformationToOverlayBounds()
186+
}
185187
}
186188
}
187189

188-
// TODO Write double tap for dynamic crop state
189190
override suspend fun onDoubleTap(
190191
pan: Offset,
191192
zoom: Float,
192193
rotation: Float,
193194
onAnimationEnd: () -> Unit
194195
) {
195-
// doubleTapped = true
196-
//
197-
// if (fling) {
198-
// resetTracking()
199-
// }
200-
// resetWithAnimation(pan = pan, zoom = zoom, rotation = rotation)
201-
// onAnimationEnd()
196+
doubleTapped = true
197+
198+
if (fling) {
199+
resetTracking()
200+
}
201+
resetWithAnimation(pan = pan, zoom = zoom, rotation = rotation)
202+
203+
animateOverlayRectTo(
204+
calculateOverlayRectInBounds(rectBounds, overlayRect)
205+
)
206+
onAnimationEnd()
202207
}
203208

204209

205210
// TODO Change pan when zoom is bigger than 1f and touchRegion is inside overlay rect
206-
// private suspend fun moveOverlayToBounds(change: PointerInputChange, newRect:Rect) {
207-
// val bounds = getBounds()
211+
// private suspend fun moveOverlayToBounds(change: PointerInputChange, newRect: Rect) {
212+
// val bounds = drawAreaRect
213+
//
208214
// val positionChange = change.positionChangeIgnoreConsumed()
209215
//
210216
// // When zoom is bigger than 100% and dynamic overlay is not at any edge of
@@ -213,27 +219,28 @@ class DynamicCropState internal constructor(
213219
// val isPanRequired = touchRegion == TouchRegion.Inside && zoom > 1f
214220
//
215221
// // Overlay moving right
216-
// if (isPanRequired && -pan.x < bounds.x && newRect.right >= containerSize.width) {
222+
// if (isPanRequired && newRect.right < bounds.right) {
223+
// println("Moving right newRect $newRect, bounds: $bounds")
217224
// snapOverlayRectTo(newRect.translate(-positionChange.x, 0f))
218225
// snapPanXto(pan.x - positionChange.x * zoom)
219226
// // Overlay moving left
220-
// } else if (isPanRequired && pan.x < bounds.x && newRect.left <= 0f) {
221-
// snapOverlayRectTo(newRect.translate(-positionChange.x, 0f))
222-
// snapPanXto(pan.x - positionChange.x * zoom)
223-
// } else if (isPanRequired && pan.y < bounds.y && newRect.top <= 0f) {
227+
// } else if (isPanRequired && pan.x < bounds.left && newRect.left <= 0f) {
228+
//// snapOverlayRectTo(newRect.translate(-positionChange.x, 0f))
229+
//// snapPanXto(pan.x - positionChange.x * zoom)
230+
// } else if (isPanRequired && pan.y < bounds.top && newRect.top <= 0f) {
224231
// // Overlay moving top
225-
// snapOverlayRectTo(newRect.translate(0f, -positionChange.y))
226-
// snapPanYto(pan.y - positionChange.y * zoom)
227-
// } else if (isPanRequired && -pan.y < bounds.y && newRect.bottom >= containerSize.height) {
232+
//// snapOverlayRectTo(newRect.translate(0f, -positionChange.y))
233+
//// snapPanYto(pan.y - positionChange.y * zoom)
234+
// } else if (isPanRequired && -pan.y < bounds.bottom && newRect.bottom >= containerSize.height) {
228235
// // Overlay moving bottom
229-
// snapOverlayRectTo(newRect.translate(0f, -positionChange.y))
230-
// snapPanYto(pan.y - positionChange.y * zoom)
236+
//// snapOverlayRectTo(newRect.translate(0f, -positionChange.y))
237+
//// snapPanYto(pan.y - positionChange.y * zoom)
231238
// } else {
232239
// snapOverlayRectTo(newRect)
233240
// }
234-
// if (touchRegion != TouchRegion.None) {
235-
// change.consume()
236-
// }
241+
//// if (touchRegion != TouchRegion.None) {
242+
//// change.consume()
243+
//// }
237244
// }
238245

239246
/**
@@ -243,7 +250,7 @@ class DynamicCropState internal constructor(
243250
* [overlayRect] might be shrunk or moved up/down/left/right to container bounds when
244251
* it's out of Composable region
245252
*/
246-
private fun moveOverlayRectToBounds(rectBounds: Rect, rectCurrent: Rect): Rect {
253+
private fun calculateOverlayRectInBounds(rectBounds: Rect, rectCurrent: Rect): Rect {
247254

248255
var width = rectCurrent.width
249256
var height = rectCurrent.height

0 commit comments

Comments
 (0)