From 166308f2f4ee1a3f69c3093b24abdde72ac6b610 Mon Sep 17 00:00:00 2001 From: Tim Huang Date: Thu, 10 Oct 2024 13:35:57 +0800 Subject: [PATCH] animation fade out when no dragging after 2 sec --- .../commonMain/kotlin/io/keeppro/Croppable.kt | 74 +++++++++++++++---- .../kotlin/io/keeppro/CroppableState.kt | 5 +- .../kotlin/io/keeppro/SudokuGrid.kt | 6 +- .../commonMain/kotlin/io/keeppro/krop/App.kt | 3 +- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt b/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt index a3c5733..29715d7 100644 --- a/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt +++ b/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt @@ -1,7 +1,10 @@ package io.keeppro +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.EnterTransition import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.updateTransition +import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.gestures.detectTapGestures @@ -20,10 +23,17 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.layout +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext /** * A croppable and zoomable layout that can handle zoom in and out with drag support, and crop image. @@ -51,14 +61,36 @@ fun Croppable( val settingTranslationY by transition.animateFloat(label = "") { it.translateY } val scope = rememberCoroutineScope() val cropWindow: Rect by state.cropWindow + var cropWindowVisible by remember { mutableStateOf(false) } + val windowStateFlow = remember { MutableStateFlow(false) } + var delayJob by remember { mutableStateOf(null) } + + LaunchedEffect(Unit){ + windowStateFlow.collectLatest { + cropWindowVisible = it + if(it){ + delayJob?.cancel() + delayJob = scope.launch { + delay(1500) + withContext(Dispatchers.Main){ + windowStateFlow.value = false + } + } + }else{ + delayJob?.cancel() + delayJob = null + } + } + } + val boxModifier = if (cropHint != null) { modifier.border(cropHint.borderWidth, cropHint.borderColor).background(cropHint.backgroundColor) } else { modifier - }.clipToBounds() - BoxWithConstraints(modifier = boxModifier) { + } + BoxWithConstraints(modifier = boxModifier.clipToBounds()) { var childWidth by remember { mutableStateOf(0) } var childHeight by remember { mutableStateOf(0) } @@ -127,6 +159,7 @@ fun Croppable( scope.launch { state.drag(pan - adjustedOffset) + windowStateFlow.value = true } } } @@ -163,20 +196,29 @@ fun Croppable( ) { content.invoke(this) } - SudokuGrid(modifier = Modifier.layout { measurable, constraints -> - val placeable = measurable.measure(constraints = constraints.copy( - maxWidth = cropWindow.width.toInt(), - maxHeight = cropWindow.height.toInt(), - minWidth = cropWindow.width.toInt(), - minHeight = cropWindow.height.toInt() - )) - layout( - width = cropWindow.width.toInt(), - height = cropWindow.height.toInt() - ) { - placeable.place((- cropWindow.topLeft.x.toInt()), (- cropWindow.topLeft.y.toInt())) - } - }) + + AnimatedVisibility( + visible = cropWindowVisible, + enter = EnterTransition.None, + exit = fadeOut() + ){ + SudokuGrid( + gridLineColor = cropHint?.gridLineColor ?: Color.Black, + modifier = Modifier.layout { measurable, constraints -> + val placeable = measurable.measure(constraints = constraints.copy( + maxWidth = cropWindow.width.toInt(), + maxHeight = cropWindow.height.toInt(), + minWidth = cropWindow.width.toInt(), + minHeight = cropWindow.height.toInt() + )) + layout( + width = cropWindow.width.toInt(), + height = cropWindow.height.toInt() + ) { + placeable.place((- cropWindow.topLeft.x.toInt()), (- cropWindow.topLeft.y.toInt())) + } + }) + } } } diff --git a/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt b/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt index 04cb378..5c0e76a 100644 --- a/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt +++ b/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt @@ -337,16 +337,19 @@ class CroppableState( } } -class CropHint( +data class CropHint( val backgroundColor: Color, val borderColor: Color, val borderWidth: Dp, + val gridLineColor: Color? ){ + companion object{ val Default = CropHint( backgroundColor = Color(0xFFBABABA), borderColor = Color(0xFFBABABA), borderWidth = 2.dp, + gridLineColor = Color.Black, ) } } \ No newline at end of file diff --git a/krop-core/src/commonMain/kotlin/io/keeppro/SudokuGrid.kt b/krop-core/src/commonMain/kotlin/io/keeppro/SudokuGrid.kt index 9ef12b5..ed84a0f 100644 --- a/krop-core/src/commonMain/kotlin/io/keeppro/SudokuGrid.kt +++ b/krop-core/src/commonMain/kotlin/io/keeppro/SudokuGrid.kt @@ -9,7 +9,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp @Composable -fun BoxScope.SudokuGrid(modifier: Modifier = Modifier) { +fun BoxScope.SudokuGrid(gridLineColor: Color, modifier: Modifier = Modifier) { Canvas(modifier = modifier) { val gridSize = 3 // For a 3x3 grid val lineThickness = 2.dp.toPx() @@ -22,14 +22,14 @@ fun BoxScope.SudokuGrid(modifier: Modifier = Modifier) { val y = i * cellSizeY if (i < gridSize) { drawLine( - color = Color.Black, + color = gridLineColor, start = Offset(x, 0f), end = Offset(x, size.height), strokeWidth = lineThickness ) } drawLine( - color = Color.Black, + color = gridLineColor, start = Offset(0f, y), end = Offset(size.width, y), strokeWidth = lineThickness diff --git a/sample-multiplatform/src/commonMain/kotlin/io/keeppro/krop/App.kt b/sample-multiplatform/src/commonMain/kotlin/io/keeppro/krop/App.kt index b580c5f..8194587 100644 --- a/sample-multiplatform/src/commonMain/kotlin/io/keeppro/krop/App.kt +++ b/sample-multiplatform/src/commonMain/kotlin/io/keeppro/krop/App.kt @@ -19,6 +19,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.layout import androidx.compose.ui.unit.dp @@ -101,7 +102,7 @@ fun CroppableSample(croppableState: CroppableState, aspectRatio: Float) { Croppable( state = croppableState, contentScale = ContentScale.Crop, - cropHint = CropHint.Default, + cropHint = CropHint.Default.copy(gridLineColor = Color.White.copy(alpha = 0.3f)), modifier = Modifier .layout { measurable, constraints -> val newConstraints = if (aspectRatio >= 1f){