mirror of
https://github.com/T8RIN/ImageToolbox.git
synced 2025-05-17 05:26:02 +08:00
Refactor predictive back usage
This commit is contained in:
@ -0,0 +1,34 @@
|
||||
package ru.tech.imageresizershrinker.core.ui.utils.helper
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
@Composable
|
||||
fun PredictiveBackObserver(
|
||||
onProgress: (Float) -> Unit,
|
||||
onClean: suspend (isCompleted: Boolean) -> Unit,
|
||||
enabled: Boolean = true
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
if (!enabled) return
|
||||
|
||||
PredictiveBackHandler { progress ->
|
||||
try {
|
||||
progress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
onClean(false)
|
||||
}
|
||||
onProgress(event.progress)
|
||||
}
|
||||
scope.launch {
|
||||
onClean(true)
|
||||
}
|
||||
} catch (_: CancellationException) {
|
||||
onClean(false)
|
||||
}
|
||||
}
|
||||
}
|
@ -28,12 +28,11 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalWindowInfo
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.t8rin.dynamic.theme.observeAsState
|
||||
@ -61,9 +60,9 @@ private fun Density.ScreenSize(
|
||||
|
||||
@Composable
|
||||
fun rememberScreenSize(): ScreenSize {
|
||||
val configuration = LocalConfiguration.current
|
||||
val windowInfo = LocalWindowInfo.current
|
||||
|
||||
var constraints by remember(configuration) {
|
||||
var constraints by remember(windowInfo) {
|
||||
mutableStateOf<Constraints?>(null)
|
||||
}
|
||||
|
||||
@ -81,12 +80,13 @@ fun rememberScreenSize(): ScreenSize {
|
||||
|
||||
val density = LocalDensity.current
|
||||
|
||||
return remember(constraints, configuration, density) {
|
||||
return remember(constraints, windowInfo, density) {
|
||||
derivedStateOf {
|
||||
with(density) {
|
||||
ScreenSize(
|
||||
width = constraints?.maxWidth?.toDp() ?: configuration.screenWidthDp.dp,
|
||||
height = constraints?.maxHeight?.toDp() ?: configuration.screenHeightDp.dp,
|
||||
width = constraints?.maxWidth?.toDp() ?: windowInfo.containerSize.height.toDp(),
|
||||
height = constraints?.maxHeight?.toDp()
|
||||
?: windowInfo.containerSize.width.toDp(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package ru.tech.imageresizershrinker.core.ui.widget.enhanced
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
@ -69,6 +68,7 @@ import androidx.compose.ui.unit.dp
|
||||
import com.t8rin.modalsheet.FullscreenPopup
|
||||
import kotlinx.coroutines.delay
|
||||
import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.alertDialogBorder
|
||||
|
||||
@Composable
|
||||
@ -223,21 +223,19 @@ fun BasicEnhancedAlertDialog(
|
||||
}
|
||||
|
||||
if (onDismissRequest != null) {
|
||||
PredictiveBackHandler(enabled = visible) { progress ->
|
||||
try {
|
||||
progress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
scale = 1f
|
||||
}
|
||||
scale = (1f - event.progress * 1.5f).coerceAtLeast(0.75f)
|
||||
PredictiveBackObserver(
|
||||
onProgress = { progress ->
|
||||
scale = (1f - progress * 1.5f).coerceAtLeast(0.75f)
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) {
|
||||
onDismissRequest()
|
||||
delay(400)
|
||||
}
|
||||
onDismissRequest()
|
||||
delay(400)
|
||||
scale = 1f
|
||||
} catch (_: Throwable) {
|
||||
scale = 1f
|
||||
}
|
||||
}
|
||||
},
|
||||
enabled = visible
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package ru.tech.imageresizershrinker.core.ui.widget.enhanced
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.AnimationSpec
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
@ -63,10 +62,10 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.animation.FancyTransitionEasing
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.ProvideContainerDefaults
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.autoElevatedBorder
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.drawHorizontalStroke
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
@Composable
|
||||
fun EnhancedModalBottomSheet(
|
||||
@ -327,21 +326,19 @@ private fun EnhancedModalSheetImpl(
|
||||
contentColor = contentColor,
|
||||
scrimColor = scrimColor,
|
||||
content = {
|
||||
if (visible && enableBackHandler) {
|
||||
PredictiveBackHandler { progress ->
|
||||
try {
|
||||
progress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
clean()
|
||||
}
|
||||
predictiveBackProgress = event.progress
|
||||
}
|
||||
PredictiveBackObserver(
|
||||
onProgress = { progress ->
|
||||
predictiveBackProgress = progress
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) {
|
||||
onVisibleChange(false)
|
||||
} catch (_: CancellationException) {
|
||||
clean()
|
||||
delay(400)
|
||||
}
|
||||
}
|
||||
}
|
||||
clean()
|
||||
},
|
||||
enabled = visible && enableBackHandler
|
||||
)
|
||||
content()
|
||||
},
|
||||
)
|
||||
@ -391,4 +388,6 @@ object EnhancedBottomSheetDefaults {
|
||||
easing = FancyTransitionEasing
|
||||
)
|
||||
|
||||
val dragHandleHeight: Dp = 4.dp
|
||||
|
||||
}
|
@ -17,22 +17,31 @@
|
||||
|
||||
package ru.tech.imageresizershrinker.core.ui.widget.enhanced
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.BottomSheetDefaults
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.drawHorizontalStroke
|
||||
import kotlin.math.tan
|
||||
|
||||
|
||||
@Composable
|
||||
@ -41,6 +50,8 @@ fun EnhancedModalSheetDragHandle(
|
||||
color: Color = EnhancedBottomSheetDefaults.barContainerColor,
|
||||
drawStroke: Boolean = true,
|
||||
showDragHandle: Boolean = true,
|
||||
bendAngle: Float = 0f,
|
||||
strokeWidth: Dp = EnhancedBottomSheetDefaults.dragHandleHeight,
|
||||
content: @Composable ColumnScope.() -> Unit = {},
|
||||
) {
|
||||
val dragHandleWidth = LocalSettingsState.current.dragHandleWidth
|
||||
@ -57,16 +68,77 @@ fun EnhancedModalSheetDragHandle(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 22.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
if (showDragHandle && dragHandleWidth > 0.dp) {
|
||||
BottomSheetDefaults.DragHandle(
|
||||
BendableDragHandle(
|
||||
width = dragHandleWidth,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(0.4f)
|
||||
angleDegrees = bendAngle,
|
||||
strokeWidth = strokeWidth,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(0.4f).compositeOver(
|
||||
MaterialTheme.colorScheme.surface
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BendableDragHandle(
|
||||
width: Dp,
|
||||
angleDegrees: Float,
|
||||
strokeWidth: Dp,
|
||||
color: Color,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val stroke = with(density) { strokeWidth.toPx() }
|
||||
val totalWidth = with(density) { width.toPx() }
|
||||
val halfWidth = totalWidth / 2f
|
||||
val halfStroke = stroke / 2f
|
||||
|
||||
val angleRadians =
|
||||
Math.toRadians((angleDegrees * (64 / width.value).coerceAtMost(1f)).toDouble()).toFloat()
|
||||
val height = tan(angleRadians) * halfWidth
|
||||
|
||||
Canvas(
|
||||
modifier = modifier
|
||||
.width(width)
|
||||
.height(height.dp + strokeWidth)
|
||||
) {
|
||||
val centerY = size.height / 2f
|
||||
val centerX = size.width / 2f
|
||||
|
||||
val leftStart = Offset(0f, centerY)
|
||||
val center = Offset(centerX, centerY + height)
|
||||
val rightEnd = Offset(size.width, centerY)
|
||||
|
||||
drawLine(
|
||||
color = color,
|
||||
start = leftStart,
|
||||
end = center,
|
||||
strokeWidth = stroke,
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
|
||||
drawLine(
|
||||
color = color,
|
||||
start = center,
|
||||
end = rightEnd,
|
||||
strokeWidth = stroke,
|
||||
cap = StrokeCap.Round
|
||||
)
|
||||
|
||||
drawCircle(
|
||||
color = color,
|
||||
radius = halfStroke,
|
||||
center = center
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -18,7 +18,6 @@
|
||||
package ru.tech.imageresizershrinker.core.ui.widget.image
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
@ -99,6 +98,7 @@ import ru.tech.imageresizershrinker.core.resources.icons.EditAlt
|
||||
import ru.tech.imageresizershrinker.core.ui.theme.White
|
||||
import ru.tech.imageresizershrinker.core.ui.theme.takeColorFromScheme
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.ContextUtils.getFilename
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.navigation.Screen
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalScreenSize
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedIconButton
|
||||
@ -460,22 +460,20 @@ fun ImagePager(
|
||||
onNavigate = onNavigate
|
||||
)
|
||||
|
||||
if (visible) {
|
||||
PredictiveBackHandler { backProgress ->
|
||||
try {
|
||||
backProgress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
predictiveBackProgress = 0f
|
||||
}
|
||||
predictiveBackProgress = event.progress
|
||||
}
|
||||
PredictiveBackObserver(
|
||||
onProgress = {
|
||||
predictiveBackProgress = it
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) {
|
||||
onDismiss()
|
||||
onUriSelected(null)
|
||||
} catch (_: Throwable) {
|
||||
predictiveBackProgress = 0f
|
||||
delay(400)
|
||||
}
|
||||
}
|
||||
}
|
||||
predictiveBackProgress = 0f
|
||||
},
|
||||
enabled = visible
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,6 @@
|
||||
|
||||
package ru.tech.imageresizershrinker.feature.libraries_info.presentation
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
@ -70,6 +69,7 @@ import com.t8rin.modalsheet.FullscreenPopup
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.delay
|
||||
import ru.tech.imageresizershrinker.core.resources.R
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.rememberLocalEssentials
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedIconButton
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedTopAppBar
|
||||
@ -253,19 +253,18 @@ fun LibrariesInfoContent(
|
||||
}
|
||||
}
|
||||
}
|
||||
PredictiveBackHandler { progress ->
|
||||
try {
|
||||
progress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
predictiveBackProgress = 0f
|
||||
}
|
||||
predictiveBackProgress = event.progress
|
||||
PredictiveBackObserver(
|
||||
onProgress = {
|
||||
predictiveBackProgress = it
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) {
|
||||
component.selectLibrary(null)
|
||||
delay(400)
|
||||
}
|
||||
component.selectLibrary(null)
|
||||
} catch (_: Throwable) {
|
||||
predictiveBackProgress = 0f
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Spacer(Modifier.fillMaxSize())
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package ru.tech.imageresizershrinker.feature.main.presentation.components
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
@ -49,6 +48,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.min
|
||||
import kotlinx.coroutines.delay
|
||||
import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.ProvidesValue
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalScreenSize
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.autoElevatedBorder
|
||||
@ -110,21 +110,19 @@ internal fun MainDrawerContent(
|
||||
}
|
||||
}
|
||||
|
||||
if ((sideSheetState.isOpen || sideSheetState.isAnimationRunning) && isSheetSlideable) {
|
||||
PredictiveBackHandler { progress ->
|
||||
try {
|
||||
progress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
clean()
|
||||
}
|
||||
predictiveBackProgress = event.progress
|
||||
}
|
||||
PredictiveBackObserver(
|
||||
onProgress = {
|
||||
predictiveBackProgress = it
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) {
|
||||
sideSheetState.close()
|
||||
} catch (_: Throwable) {
|
||||
clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
clean()
|
||||
},
|
||||
enabled = (sideSheetState.isOpen || sideSheetState.isAnimationRunning) && isSheetSlideable
|
||||
)
|
||||
|
||||
val autoElevation by animateDpAsState(
|
||||
if (settingsState.drawContainerShadows) 16.dp
|
||||
else 0.dp
|
||||
|
@ -18,7 +18,6 @@
|
||||
package ru.tech.imageresizershrinker.feature.media_picker.presentation.components
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
@ -98,6 +97,7 @@ import ru.tech.imageresizershrinker.core.resources.R
|
||||
import ru.tech.imageresizershrinker.core.resources.icons.BrokenImageAlt
|
||||
import ru.tech.imageresizershrinker.core.ui.theme.White
|
||||
import ru.tech.imageresizershrinker.core.ui.theme.takeColorFromScheme
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalScreenSize
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedIconButton
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedTopAppBar
|
||||
@ -426,21 +426,19 @@ internal fun MediaImagePager(
|
||||
}
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
PredictiveBackHandler { backProgress ->
|
||||
try {
|
||||
backProgress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
predictiveBackProgress = 0f
|
||||
}
|
||||
predictiveBackProgress = event.progress
|
||||
}
|
||||
PredictiveBackObserver(
|
||||
onProgress = {
|
||||
predictiveBackProgress = it
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) {
|
||||
onDismiss()
|
||||
} catch (_: Throwable) {
|
||||
predictiveBackProgress = 0f
|
||||
delay(400)
|
||||
}
|
||||
}
|
||||
}
|
||||
predictiveBackProgress = 0f
|
||||
},
|
||||
enabled = visible
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -17,11 +17,12 @@
|
||||
|
||||
package ru.tech.imageresizershrinker.feature.root.presentation.components
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.BackdropScaffold
|
||||
import androidx.compose.material.BackdropValue
|
||||
@ -34,11 +35,9 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
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.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
@ -47,17 +46,16 @@ import com.smarttoolfactory.gesture.detectPointerTransformGestures
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.tech.imageresizershrinker.core.settings.domain.model.FastSettingsSide
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.animation.FancyTransitionEasing
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.navigation.Screen
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalScreenSize
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedModalSheetDragHandle
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.animateShape
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.toShape
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.modifier.withLayoutCorners
|
||||
import ru.tech.imageresizershrinker.feature.settings.presentation.SettingsContent
|
||||
import ru.tech.imageresizershrinker.feature.settings.presentation.screenLogic.SettingsComponent
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
@Composable
|
||||
internal fun SettingsBackdropWrapper(
|
||||
@ -66,7 +64,7 @@ internal fun SettingsBackdropWrapper(
|
||||
settingsComponent: SettingsComponent,
|
||||
children: @Composable () -> Unit
|
||||
) {
|
||||
var shape by remember { mutableStateOf<RoundedCornerShape>(RoundedCornerShape(0.dp)) }
|
||||
var shape by remember { mutableStateOf(RoundedCornerShape(0.dp)) }
|
||||
val scaffoldState = rememberBackdropScaffoldState(
|
||||
initialValue = BackdropValue.Concealed,
|
||||
animationSpec = tween(
|
||||
@ -104,7 +102,6 @@ internal fun SettingsBackdropWrapper(
|
||||
}
|
||||
}
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val isTargetRevealed = scaffoldState.targetValue == BackdropValue.Revealed
|
||||
|
||||
BackdropScaffold(
|
||||
@ -115,7 +112,6 @@ internal fun SettingsBackdropWrapper(
|
||||
},
|
||||
appBar = {},
|
||||
frontLayerContent = {
|
||||
|
||||
val alpha by animateFloatAsState(
|
||||
if (isTargetRevealed) 1f else 0f
|
||||
)
|
||||
@ -162,37 +158,35 @@ internal fun SettingsBackdropWrapper(
|
||||
canExpandSettings = canExpandSettings
|
||||
)
|
||||
|
||||
val progress = scaffoldState.progress(
|
||||
from = BackdropValue.Revealed,
|
||||
to = BackdropValue.Concealed
|
||||
) * 20f
|
||||
|
||||
EnhancedModalSheetDragHandle(
|
||||
color = Color.Transparent,
|
||||
drawStroke = false,
|
||||
bendAngle = (-15f * (1f - progress)).coerceAtMost(0f),
|
||||
modifier = Modifier.alpha(alpha)
|
||||
)
|
||||
}
|
||||
},
|
||||
backLayerContent = {
|
||||
if (canExpandSettings && (scaffoldState.isRevealed || isTargetRevealed)) {
|
||||
if (isTargetRevealed) {
|
||||
PredictiveBackHandler { progress ->
|
||||
try {
|
||||
progress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
clean()
|
||||
}
|
||||
predictiveBackProgress = event.progress * 1.3f
|
||||
}
|
||||
scope.launch {
|
||||
scaffoldState.conceal()
|
||||
clean()
|
||||
}
|
||||
} catch (_: CancellationException) {
|
||||
clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
PredictiveBackObserver(
|
||||
onProgress = {
|
||||
predictiveBackProgress = it * 1.3f
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) scaffoldState.conceal()
|
||||
clean()
|
||||
},
|
||||
enabled = isTargetRevealed
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(shape)
|
||||
.fillMaxWidth()
|
||||
.height(LocalScreenSize.current.height)
|
||||
.alpha(1f - animatedPredictiveBackProgress)
|
||||
) {
|
||||
SettingsContent(
|
||||
@ -205,13 +199,10 @@ internal fun SettingsBackdropWrapper(
|
||||
headerHeight = 70.dp,
|
||||
persistentAppBar = false,
|
||||
frontLayerElevation = 0.dp,
|
||||
backLayerBackgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
backLayerBackgroundColor = MaterialTheme.colorScheme.surface,
|
||||
frontLayerBackgroundColor = MaterialTheme.colorScheme.surface,
|
||||
frontLayerScrimColor = Color.Transparent,
|
||||
frontLayerShape = animateShape(
|
||||
if (scaffoldState.isRevealed) shape
|
||||
else RoundedCornerShape(0.dp)
|
||||
),
|
||||
frontLayerShape = RoundedCornerShape(0.dp),
|
||||
gesturesEnabled = scaffoldState.isRevealed
|
||||
)
|
||||
}
|
@ -45,6 +45,7 @@ import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
|
||||
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
||||
@ -84,7 +85,6 @@ import ru.tech.imageresizershrinker.core.settings.presentation.model.SettingsGro
|
||||
import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState
|
||||
import ru.tech.imageresizershrinker.core.ui.theme.blend
|
||||
import ru.tech.imageresizershrinker.core.ui.theme.takeColorFromScheme
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.plus
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.navigation.Screen
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalScreenSize
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedIconButton
|
||||
@ -109,6 +109,7 @@ import ru.tech.imageresizershrinker.feature.settings.presentation.screenLogic.Se
|
||||
@Composable
|
||||
fun SettingsContent(
|
||||
component: SettingsComponent,
|
||||
disableBottomInsets: Boolean = false,
|
||||
appBarNavigationIcon: (@Composable (Boolean, () -> Unit) -> Unit)? = null
|
||||
) {
|
||||
val isStandaloneScreen = appBarNavigationIcon == null
|
||||
@ -126,20 +127,26 @@ fun SettingsContent(
|
||||
val loading = component.isFilteringSettings
|
||||
|
||||
val padding = WindowInsets.navigationBars
|
||||
.union(WindowInsets.displayCutout)
|
||||
.let { insets ->
|
||||
if (disableBottomInsets) {
|
||||
insets.only(
|
||||
WindowInsetsSides.Horizontal + WindowInsetsSides.Top
|
||||
)
|
||||
} else {
|
||||
insets
|
||||
}
|
||||
}
|
||||
.asPaddingValues()
|
||||
.plus(
|
||||
WindowInsets.displayCutout
|
||||
.asPaddingValues()
|
||||
.run {
|
||||
PaddingValues(
|
||||
top = 8.dp,
|
||||
bottom = calculateBottomPadding() + 8.dp,
|
||||
end = calculateEndPadding(layoutDirection) + 8.dp,
|
||||
start = if (isStandaloneScreen) calculateStartPadding(layoutDirection) + 8.dp
|
||||
else 8.dp
|
||||
)
|
||||
}
|
||||
)
|
||||
.run {
|
||||
PaddingValues(
|
||||
top = 8.dp,
|
||||
bottom = calculateBottomPadding() + 8.dp,
|
||||
end = calculateEndPadding(layoutDirection) + 8.dp,
|
||||
start = if (isStandaloneScreen) calculateStartPadding(layoutDirection) + 8.dp
|
||||
else 8.dp
|
||||
)
|
||||
}
|
||||
|
||||
val focus = LocalFocusManager.current
|
||||
val isKeyboardVisible by isKeyboardVisibleAsState()
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package ru.tech.imageresizershrinker.feature.single_edit.presentation.components
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
@ -74,6 +73,7 @@ import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.tech.imageresizershrinker.core.resources.R
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.helper.PredictiveBackObserver
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalScreenSize
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.provider.ProvideContainerDefaults
|
||||
import ru.tech.imageresizershrinker.core.ui.widget.dialogs.ExitBackHandler
|
||||
@ -335,19 +335,18 @@ fun FullscreenEditOption(
|
||||
}
|
||||
if (visible) {
|
||||
if (canGoBack) {
|
||||
PredictiveBackHandler { progress ->
|
||||
try {
|
||||
progress.collect { event ->
|
||||
if (event.progress <= 0.05f) {
|
||||
predictiveBackProgress = 0f
|
||||
}
|
||||
predictiveBackProgress = event.progress
|
||||
PredictiveBackObserver(
|
||||
onProgress = {
|
||||
predictiveBackProgress = it
|
||||
},
|
||||
onClean = { isCompleted ->
|
||||
if (isCompleted) {
|
||||
internalOnDismiss()
|
||||
delay(400)
|
||||
}
|
||||
internalOnDismiss()
|
||||
} catch (_: Throwable) {
|
||||
predictiveBackProgress = 0f
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
ExitBackHandler(onBack = internalOnDismiss)
|
||||
}
|
||||
|
Reference in New Issue
Block a user