@@ -11,7 +11,11 @@ import androidx.compose.animation.fadeOut
1111import androidx.compose.animation.togetherWith
1212import androidx.compose.foundation.Image
1313import androidx.compose.foundation.background
14+ import androidx.compose.foundation.clickable
15+ import androidx.compose.foundation.gestures.AnchoredDraggableState
16+ import androidx.compose.foundation.gestures.DraggableAnchors
1417import androidx.compose.foundation.gestures.Orientation
18+ import androidx.compose.foundation.gestures.anchoredDraggable
1519import androidx.compose.foundation.layout.Arrangement
1620import androidx.compose.foundation.layout.Box
1721import androidx.compose.foundation.layout.BoxScope
@@ -66,8 +70,11 @@ import com.getcode.R
6670import com.getcode.theme.CodeTheme
6771import com.getcode.theme.White
6872import com.getcode.theme.White50
73+ import com.getcode.util.addIf
74+ import com.getcode.util.toPx
6975import kotlinx.coroutines.delay
7076import kotlin.math.roundToInt
77+ import kotlin.time.Duration.Companion.seconds
7178
7279object SlideToConfirmDefaults {
7380 @Composable
@@ -88,6 +95,8 @@ object SlideToConfirmDefaults {
8895 )
8996 }
9097
98+
99+ val SnapThreshold = 0.7f
91100 val BlueTrackColor = Track .BlueColor
92101 val BlackTrackColor = Track .BlackColor
93102}
@@ -96,7 +105,7 @@ private object Thumb {
96105 val Size : Dp
97106 @Composable get() = CodeTheme .dimens.grid.x12
98107 val Color = androidx.compose.ui.graphics.Color .White
99- val Shape : Shape
108+ val Shape : Shape
100109 @Composable get() = CodeTheme .shapes.small
101110}
102111
@@ -135,20 +144,20 @@ fun SlideToConfirm(
135144 val hapticFeedback = LocalHapticFeedback .current
136145 val swipeState = rememberSwipeableState(
137146 initialValue = if (loading) Anchor .End else Anchor .Start ,
138- confirmStateChange = { anchor ->
139- if (anchor == Anchor .End ) {
140- hapticFeedback.performHapticFeedback(HapticFeedbackType .LongPress )
141- loading = true
142- onConfirm()
143- }
144- true
145- }
146147 )
147148
148149 val swipeFraction by remember {
149150 derivedStateOf { calculateSwipeFraction(swipeState.progress) }
150151 }
151152
153+ LaunchedEffect (swipeFraction) {
154+ if (swipeFraction == 1f ) {
155+ hapticFeedback.performHapticFeedback(HapticFeedbackType .LongPress )
156+ loading = true
157+ onConfirm()
158+ }
159+ }
160+
152161 LaunchedEffect (loading) {
153162 swipeState.animateTo(if (loading) Anchor .End else Anchor .Start )
154163 }
@@ -174,6 +183,7 @@ fun SlideToConfirm(
174183 .align(Alignment .Center ),
175184 )
176185 }
186+
177187 loading -> {
178188 CodeCircularProgressIndicator (
179189 strokeWidth = CodeTheme .dimens.thickBorder,
@@ -209,9 +219,7 @@ private fun calculateSwipeFraction(progress: SwipeProgress<Anchor>): Float {
209219 } else {
210220 if (fromStart) progress.fraction else 1f - progress.fraction
211221 }
212- }
213-
214- enum class Anchor { Start , End }
222+ }enum class Anchor { Start , End }
215223
216224@Composable
217225private fun Track (
@@ -233,7 +241,7 @@ private fun Track(
233241 with (density) { fullWidth - (2 * horizontalPadding + thumbSize).toPx() }
234242 }
235243
236- val snapThreshold = 0.8f
244+ val snapThreshold = SlideToConfirmDefaults . SnapThreshold
237245 val thresholds = { from: Anchor , _: Anchor ->
238246 if (from == Anchor .Start ) {
239247 FractionalThreshold (snapThreshold)
@@ -314,11 +322,20 @@ private fun Preview() {
314322 Column (
315323 modifier = Modifier
316324 .background(Color .Black )
317- .padding(horizontal = CodeTheme .dimens.inset, vertical = CodeTheme .dimens.grid.x6),
325+ .padding(
326+ horizontal = CodeTheme .dimens.inset,
327+ vertical = CodeTheme .dimens.grid.x6
328+ ),
318329 horizontalAlignment = Alignment .CenterHorizontally ,
319330 verticalArrangement = Arrangement .spacedBy(CodeTheme .dimens.grid.x3)
320331 ) {
321332 SlideToConfirm (
333+ modifier = Modifier .addIf(isSuccess) {
334+ Modifier .clickable {
335+ isLoading = false
336+ isSuccess = false
337+ }
338+ },
322339 isLoading = isLoading,
323340 isSuccess = isSuccess,
324341 onConfirm = { isLoading = true },
0 commit comments