PredictiveBack for ModalNavigationDrawer, SideDrawer
This commit is contained in:
1 parent
6f6461e855
commit
d69df5f7ab
3 files changed
+54
-11
No files matched your search
@@ -30,6 +30,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.input.pointer.positionChange
|
||||
@@ -42,6 +43,8 @@ import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.lerp
|
||||
import com.hippo.ehviewer.ui.tools.animateFloatMergeOneWayPredictiveBackAsState
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -306,6 +309,16 @@ fun ModalNavigationDrawer(
|
||||
},
|
||||
color = scrimColor,
|
||||
)
|
||||
val predictiveState by animateFloatMergeOneWayPredictiveBackAsState(drawerState.isOpen) {
|
||||
drawerState.close()
|
||||
}
|
||||
val predictiveModifier = if (drawerState.isOpen) {
|
||||
Modifier.scale(lerp(1f, 0.9f, predictiveState)).offset {
|
||||
IntOffset(lerp(0f, minValue * 0.05f, predictiveState).roundToInt(), 0)
|
||||
}
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.offset {
|
||||
IntOffset(drawerState.requireOffset().roundToInt(), 0)
|
||||
@@ -314,7 +327,7 @@ fun ModalNavigationDrawer(
|
||||
if (w != 0) {
|
||||
minValue = -it.size.width.toFloat()
|
||||
}
|
||||
},
|
||||
} then predictiveModifier,
|
||||
) {
|
||||
drawerContent()
|
||||
}
|
||||
@@ -398,6 +411,16 @@ fun SideDrawer(
|
||||
},
|
||||
color = scrimColor,
|
||||
)
|
||||
val predictiveState by animateFloatMergeOneWayPredictiveBackAsState(drawerState.isOpen) {
|
||||
drawerState.close()
|
||||
}
|
||||
val predictiveModifier = if (drawerState.isOpen) {
|
||||
Modifier.scale(lerp(1f, 0.9f, predictiveState)).offset {
|
||||
IntOffset(lerp(0f, minValue * 0.05f, predictiveState).roundToInt(), 0)
|
||||
}
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.offset {
|
||||
IntOffset(drawerState.requireOffset().roundToInt(), 0)
|
||||
@@ -406,7 +429,7 @@ fun SideDrawer(
|
||||
if (w != 0) {
|
||||
minValue = it.size.width.toFloat()
|
||||
}
|
||||
}.align(Alignment.TopEnd),
|
||||
}.align(Alignment.TopEnd) then predictiveModifier,
|
||||
) {
|
||||
drawerContent()
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.Image
|
||||
@@ -300,9 +299,6 @@ class MainActivity : EhActivity() {
|
||||
recomposeScope.invalidate()
|
||||
}
|
||||
}
|
||||
BackHandler(drawerState.isOpen) {
|
||||
closeDrawer()
|
||||
}
|
||||
LocalTouchSlopProvider(Settings.touchSlopFactor.toFloat()) {
|
||||
ModalNavigationDrawer(
|
||||
drawerContent = {
|
||||
@@ -355,11 +351,6 @@ class MainActivity : EhActivity() {
|
||||
sideDrawerState.open()
|
||||
}
|
||||
}
|
||||
BackHandler(sideDrawerState.isOpen) {
|
||||
scope.launch {
|
||||
sideDrawerState.close()
|
||||
}
|
||||
}
|
||||
SideDrawer(
|
||||
drawerContent = {
|
||||
if (sheet != null) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import eu.kanade.tachiyomi.util.lang.withNonCancellableContext
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -72,3 +73,31 @@ fun animateFloatMergePredictiveBackAsState(
|
||||
}
|
||||
return animatable.asState()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun animateFloatMergeOneWayPredictiveBackAsState(
|
||||
enable: Boolean,
|
||||
animationSpec: AnimationSpec<Float> = spring(),
|
||||
predictiveBackInterpolator: Easing = EaseOut,
|
||||
onBack: suspend () -> Unit,
|
||||
): State<Float> {
|
||||
val animatable = remember { Animatable(0f, Float.VectorConverter) }
|
||||
PredictiveBackHandler(enable) { progress ->
|
||||
try {
|
||||
progress.collect {
|
||||
val transformed = predictiveBackInterpolator.transform(it.progress)
|
||||
animatable.snapTo(transformed)
|
||||
}
|
||||
} catch (e: CancellationException) {
|
||||
withNonCancellableContext {
|
||||
animatable.animateTo(0f, animationSpec)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
withNonCancellableContext {
|
||||
onBack()
|
||||
animatable.snapTo(0f)
|
||||
}
|
||||
}
|
||||
return animatable.asState()
|
||||
}
|
||||
Reference in new issue
Block a user