diff --git a/app/src/main/kotlin/androidx/navigation/compose/NavHost.kt b/app/src/main/kotlin/androidx/navigation/compose/NavHost.kt index fb40114d5..5db588dd0 100644 --- a/app/src/main/kotlin/androidx/navigation/compose/NavHost.kt +++ b/app/src/main/kotlin/androidx/navigation/compose/NavHost.kt @@ -17,6 +17,7 @@ package androidx.navigation.compose import android.annotation.SuppressLint +import androidx.activity.compose.BackHandler import androidx.activity.compose.PredictiveBackHandler import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope @@ -53,6 +54,8 @@ import androidx.navigation.NavHostController import androidx.navigation.Navigator import androidx.navigation.createGraph import androidx.navigation.get +import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.collectAsState import kotlin.math.roundToLong import kotlinx.coroutines.CancellationException import kotlinx.coroutines.NonCancellable @@ -280,54 +283,63 @@ public fun NavHost( } } - val duration = 500000000L - val transitionState = remember { MutableTransitionState(backStackEntry) } - val transition = updateTransition(transitionState = transitionState, label = "entry") - val animatedFraction = remember { Animatable(0f).also { it.updateBounds(lowerBound = 0f, upperBound = 1f) } } + val enablePredictiveBack by Settings.predictiveNavAnim.collectAsState() + val transition = if (enablePredictiveBack) { + val duration = 500000000L + val transitionState = remember { MutableTransitionState(backStackEntry) } + val transition = updateTransition(transitionState = transitionState, label = "entry") + val animatedFraction = remember { Animatable(0f).also { it.updateBounds(lowerBound = 0f, upperBound = 1f) } } - fun seekToFraction(lState: NavBackStackEntry, rState: NavBackStackEntry) { - val fraction = animatedFraction.value - val playTimeNanos = (fraction * duration).roundToLong() - transition.setPlaytimeAfterInitialAndTargetStateEstablished(lState, rState, playTimeNanos) - } + fun seekToFraction(lState: NavBackStackEntry, rState: NavBackStackEntry) { + val fraction = animatedFraction.value + val playTimeNanos = (fraction * duration).roundToLong() + transition.setPlaytimeAfterInitialAndTargetStateEstablished(lState, rState, playTimeNanos) + } - LaunchedEffect(backStackEntry) { - try { - animatedFraction.animateTo(1f, animationSpec = tween(500, easing = LinearEasing)) { - seekToFraction(transitionState.currentState, backStackEntry) - } - } finally { - withContext(NonCancellable) { - animatedFraction.snapTo(0f) - transition.setPlaytimeAfterInitialAndTargetStateEstablished( - backStackEntry, - backStackEntry, - 0, - ) + LaunchedEffect(backStackEntry) { + try { + animatedFraction.animateTo(1f, animationSpec = tween(500, easing = LinearEasing)) { + seekToFraction(transitionState.currentState, backStackEntry) + } + } finally { + withContext(NonCancellable) { + animatedFraction.snapTo(0f) + transition.setPlaytimeAfterInitialAndTargetStateEstablished( + backStackEntry, + backStackEntry, + 0, + ) + } } } - } - PredictiveBackHandler(currentBackStack.size > 1) { flow -> - // Prev can never be null, i.e. BackHandler should not enabled when prev is null - val prev = currentBackStack.last { it != backStackEntry } - try { - flow.collect { - val interpolated = EaseOut.transform(it.progress) - animatedFraction.snapTo(interpolated) - seekToFraction(backStackEntry, prev) + PredictiveBackHandler(currentBackStack.size > 1) { flow -> + // Prev can never be null, i.e. BackHandler should not enabled when prev is null + val prev = currentBackStack.last { it != backStackEntry } + try { + flow.collect { + val interpolated = EaseOut.transform(it.progress) + animatedFraction.snapTo(interpolated) + seekToFraction(backStackEntry, prev) + } + navController.popBackStack() + } catch (e: CancellationException) { + withContext(NonCancellable) { + animatedFraction.snapTo(0f) + transition.setPlaytimeAfterInitialAndTargetStateEstablished( + backStackEntry, + backStackEntry, + 0, + ) + } } + } + transition + } else { + BackHandler(currentBackStack.size > 1) { navController.popBackStack() - } catch (e: CancellationException) { - withContext(NonCancellable) { - animatedFraction.snapTo(0f) - transition.setPlaytimeAfterInitialAndTargetStateEstablished( - backStackEntry, - backStackEntry, - 0, - ) - } } + updateTransition(backStackEntry, label = "entry") } transition.AnimatedContent( diff --git a/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt b/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt index 6de45f644..87f5ed17f 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/Settings.kt @@ -106,6 +106,7 @@ object Settings : DataStorePreferences(null) { val thumbColumns = intPref("thumb_columns", 3) val listThumbSize = intPref("list_tile_size", 40) val meteredNetworkWarning = boolPref("cellular_network_warning", false) + val predictiveNavAnim = boolPref("predictive_nav_anim", true) val needSignInFlow: Flow var downloadScheme by stringOrNullPref("image_scheme", null) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt index d80f7692a..f99315f26 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt @@ -141,6 +141,10 @@ fun AdvancedScreen(navigator: DestinationsNavigator) { title = stringResource(id = R.string.preload_thumb_aggressively), value = Settings::preloadThumbAggressively, ) + SwitchPreference( + title = stringResource(id = R.string.predictive_nav_anim), + value = Settings.predictiveNavAnim::value, + ) IntSliderPreference( maxValue = 5, minValue = 1, diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 2e02ea4e5..9b47ef212 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -524,6 +524,7 @@ 详情模式下缩略图大小 账户 激进地预载缩略图 + 启用预见式返回导航动画 自动检查更新 从不 每天 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 03c28ae91..78e888de3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -587,6 +587,7 @@ Thumb size in thumb mode Account Preload thumbs aggressively + Enable predictive back navigation animation User Agent Automatically check for updates Never