From 8f937b1ddab111168013b0e21d296a4a275ada50 Mon Sep 17 00:00:00 2001 From: Tim Huang Date: Thu, 10 Oct 2024 18:15:27 +0800 Subject: [PATCH] build a standalone CropHintWindow --- .../commonMain/kotlin/io/keeppro/Croppable.kt | 60 ++----------- .../kotlin/io/keeppro/CroppableState.kt | 2 +- .../io/keeppro/widget/CropHintWindow.kt | 84 +++++++++++++++++++ .../io/keeppro/{ => widget}/SudokuGrid.kt | 2 +- 4 files changed, 93 insertions(+), 55 deletions(-) create mode 100644 krop-core/src/commonMain/kotlin/io/keeppro/widget/CropHintWindow.kt rename krop-core/src/commonMain/kotlin/io/keeppro/{ => widget}/SudokuGrid.kt (97%) diff --git a/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt b/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt index 29715d7..8f330cc 100644 --- a/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt +++ b/krop-core/src/commonMain/kotlin/io/keeppro/Croppable.kt @@ -1,10 +1,7 @@ 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 @@ -22,18 +19,12 @@ import androidx.compose.runtime.setValue 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 io.keeppro.widget.CropHintWindow 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. @@ -60,29 +51,7 @@ fun Croppable( val settingTranslationX by transition.animateFloat(label = "") { it.translateX } 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) { @@ -197,27 +166,12 @@ fun Croppable( content.invoke(this) } - 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())) - } - }) + if (cropHint != null){ + CropHintWindow( + cropHint.gridLineColor, + state.cropWindow.value, + windowStateFlow, + ) } } diff --git a/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt b/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt index 5c0e76a..1be9021 100644 --- a/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt +++ b/krop-core/src/commonMain/kotlin/io/keeppro/CroppableState.kt @@ -341,7 +341,7 @@ data class CropHint( val backgroundColor: Color, val borderColor: Color, val borderWidth: Dp, - val gridLineColor: Color? + val gridLineColor: Color ){ companion object{ diff --git a/krop-core/src/commonMain/kotlin/io/keeppro/widget/CropHintWindow.kt b/krop-core/src/commonMain/kotlin/io/keeppro/widget/CropHintWindow.kt new file mode 100644 index 0000000..ae8174a --- /dev/null +++ b/krop-core/src/commonMain/kotlin/io/keeppro/widget/CropHintWindow.kt @@ -0,0 +1,84 @@ +package io.keeppro.widget + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.Color +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 + +@Composable +fun BoxScope.CropHintWindow( + gridLineColor: Color, + cropWindow: Rect, + windowStateFlow: MutableStateFlow, +) { + var cropWindowVisible by remember { mutableStateOf(false) } + var delayJob by remember { mutableStateOf(null) } + val scope = rememberCoroutineScope() + + 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 + } + } + } + + + AnimatedVisibility( + visible = cropWindowVisible, + enter = EnterTransition.None, + exit = fadeOut() + ) { + + SudokuGrid( + gridLineColor = gridLineColor, + 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()) + ) + } + }) + } + +} \ 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/widget/SudokuGrid.kt similarity index 97% rename from krop-core/src/commonMain/kotlin/io/keeppro/SudokuGrid.kt rename to krop-core/src/commonMain/kotlin/io/keeppro/widget/SudokuGrid.kt index ed84a0f..2a2a7de 100644 --- a/krop-core/src/commonMain/kotlin/io/keeppro/SudokuGrid.kt +++ b/krop-core/src/commonMain/kotlin/io/keeppro/widget/SudokuGrid.kt @@ -1,4 +1,4 @@ -package io.keeppro +package io.keeppro.widget import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.BoxScope