Browse Source

Revert "Implement predictive back animation (#10273)"

This reverts commit 9c120e623193271971448fb03665a73dff4f85cb.

Potentially too buggy for a stable release for now.
arkon 1 year ago
parent
commit
dba5e6fbfd

+ 2 - 8
app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt

@@ -273,10 +273,7 @@ private fun MangaScreenSmallImpl(
             onBackClicked()
         }
     }
-    BackHandler(
-        enabled = isAnySelected,
-        onBack = { onAllChapterSelected(false) },
-    )
+    BackHandler(onBack = internalOnBackPressed)
 
     Scaffold(
         topBar = {
@@ -530,10 +527,7 @@ fun MangaScreenLargeImpl(
             onBackClicked()
         }
     }
-    BackHandler(
-        enabled = isAnySelected,
-        onBack = { onAllChapterSelected(false) },
-    )
+    BackHandler(onBack = internalOnBackPressed)
 
     Scaffold(
         topBar = {

+ 1 - 32
app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt

@@ -3,10 +3,6 @@ package eu.kanade.presentation.manga.components
 import android.graphics.Bitmap
 import android.graphics.drawable.BitmapDrawable
 import android.os.Build
-import androidx.activity.compose.PredictiveBackHandler
-import androidx.compose.animation.core.LinearOutSlowInEasing
-import androidx.compose.animation.core.animate
-import androidx.compose.animation.core.tween
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
@@ -29,18 +25,15 @@ import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.DpOffset
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.lerp
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.compose.ui.window.Dialog
 import androidx.compose.ui.window.DialogProperties
@@ -55,13 +48,11 @@ import eu.kanade.presentation.components.DropdownMenu
 import eu.kanade.presentation.manga.EditCoverAction
 import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
 import kotlinx.collections.immutable.persistentListOf
-import soup.compose.material.motion.MotionConstants
 import tachiyomi.domain.manga.model.Manga
 import tachiyomi.i18n.MR
 import tachiyomi.presentation.core.components.material.Scaffold
 import tachiyomi.presentation.core.i18n.stringResource
 import tachiyomi.presentation.core.util.clickableNoIndication
-import kotlin.coroutines.cancellation.CancellationException
 
 @Composable
 fun MangaCoverDialog(
@@ -160,32 +151,10 @@ fun MangaCoverDialog(
             val statusBarPaddingPx = with(LocalDensity.current) { contentPadding.calculateTopPadding().roundToPx() }
             val bottomPaddingPx = with(LocalDensity.current) { contentPadding.calculateBottomPadding().roundToPx() }
 
-            var scale by remember { mutableFloatStateOf(1f) }
-            PredictiveBackHandler { progress ->
-                try {
-                    progress.collect { backEvent ->
-                        scale = lerp(1f, 0.8f, LinearOutSlowInEasing.transform(backEvent.progress))
-                    }
-                    onDismissRequest()
-                } catch (e: CancellationException) {
-                    animate(
-                        initialValue = scale,
-                        targetValue = 1f,
-                        animationSpec = tween(durationMillis = MotionConstants.DefaultMotionDuration),
-                    ) { value, _ ->
-                        scale = value
-                    }
-                }
-            }
-
             Box(
                 modifier = Modifier
                     .fillMaxSize()
-                    .clickableNoIndication(onClick = onDismissRequest)
-                    .graphicsLayer {
-                        scaleX = scale
-                        scaleY = scale
-                    },
+                    .clickableNoIndication(onClick = onDismissRequest),
             ) {
                 AndroidView(
                     factory = {

+ 10 - 344
app/src/main/java/eu/kanade/presentation/util/Navigator.kt

@@ -1,54 +1,13 @@
 package eu.kanade.presentation.util
 
 import android.annotation.SuppressLint
-import androidx.activity.BackEventCompat
-import androidx.activity.compose.PredictiveBackHandler
 import androidx.compose.animation.AnimatedContent
 import androidx.compose.animation.AnimatedContentTransitionScope
 import androidx.compose.animation.ContentTransform
-import androidx.compose.animation.EnterTransition
-import androidx.compose.animation.ExitTransition
-import androidx.compose.animation.core.FastOutSlowInEasing
-import androidx.compose.animation.core.LinearOutSlowInEasing
-import androidx.compose.animation.core.animate
-import androidx.compose.animation.core.tween
-import androidx.compose.animation.togetherWith
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.ProvidableCompositionLocal
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.movableContentOf
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
 import androidx.compose.runtime.staticCompositionLocalOf
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.drawWithCache
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.BlurEffect
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.ColorMatrix
-import androidx.compose.ui.graphics.Paint
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.graphics.TransformOrigin
-import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
-import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.layout.onSizeChanged
-import androidx.compose.ui.platform.LocalView
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.toSize
-import androidx.compose.ui.util.lerp
-import androidx.compose.ui.zIndex
 import cafe.adriel.voyager.core.model.ScreenModel
 import cafe.adriel.voyager.core.model.ScreenModelStore
 import cafe.adriel.voyager.core.screen.Screen
@@ -57,25 +16,14 @@ import cafe.adriel.voyager.core.screen.uniqueScreenKey
 import cafe.adriel.voyager.core.stack.StackEvent
 import cafe.adriel.voyager.navigator.Navigator
 import cafe.adriel.voyager.transitions.ScreenTransitionContent
-import eu.kanade.tachiyomi.util.view.getWindowRadius
 import kotlinx.coroutines.CoroutineName
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
 import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
 import kotlinx.coroutines.cancel
-import kotlinx.coroutines.flow.onCompletion
-import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.launch
 import kotlinx.coroutines.plus
-import soup.compose.material.motion.MotionConstants
 import soup.compose.material.motion.animation.materialSharedAxisX
 import soup.compose.material.motion.animation.rememberSlideDistance
-import kotlin.coroutines.cancellation.CancellationException
-import kotlin.math.PI
-import kotlin.math.sin
 
 /**
  * For invoking back press to the parent activity
@@ -109,299 +57,17 @@ interface AssistContentScreen {
 }
 
 @Composable
-fun DefaultNavigatorScreenTransition(
-    navigator: Navigator,
-    modifier: Modifier = Modifier,
-) {
-    val scope = rememberCoroutineScope()
-    val view = LocalView.current
-    val handler = remember {
-        OnBackHandler(
-            scope = scope,
-            windowCornerRadius = view.getWindowRadius(),
-            onBackPressed = navigator::pop,
-        )
-    }
-    PredictiveBackHandler(enabled = navigator.canPop) { progress ->
-        progress
-            .onStart { handler.reset() }
-            .onCompletion { e ->
-                if (e == null) {
-                    handler.onBackConfirmed()
-                } else {
-                    handler.onBackCancelled()
-                }
-            }
-            .collect(handler::onBackEvent)
-    }
-
-    Box(modifier = modifier.onSizeChanged { handler.updateContainerSize(it.toSize()) }) {
-        val currentSceneEntry = navigator.lastItem
-        val showPrev by remember {
-            derivedStateOf { handler.scale < 1f || handler.translationY != 0f }
-        }
-        val visibleItems = remember(currentSceneEntry, showPrev) {
-            if (showPrev) {
-                val prevSceneEntry = navigator.items.getOrNull(navigator.size - 2)
-                listOfNotNull(currentSceneEntry, prevSceneEntry)
-            } else {
-                listOfNotNull(currentSceneEntry)
-            }
-        }
-
-        val slideDistance = rememberSlideDistance()
-
-        val screenContent = remember {
-            movableContentOf<Screen> { screen ->
-                navigator.saveableState("transition", screen) {
-                    screen.Content()
-                }
-            }
-        }
-
-        visibleItems.forEachIndexed { index, backStackEntry ->
-            val isPrev = index == 1 && visibleItems.size > 1
-            if (!isPrev) {
-                AnimatedContent(
-                    targetState = backStackEntry,
-                    transitionSpec = {
-                        val forward = navigator.lastEvent != StackEvent.Pop
-                        if (!forward && !handler.isReady) {
-                            // Pop screen without animation when predictive back is in use
-                            EnterTransition.None togetherWith ExitTransition.None
-                        } else {
-                            materialSharedAxisX(
-                                forward = forward,
-                                slideDistance = slideDistance,
-                            )
-                        }
-                    },
-                    modifier = Modifier
-                        .zIndex(1f)
-                        .graphicsLayer {
-                            this.alpha = handler.alpha
-                            this.transformOrigin = TransformOrigin(
-                                pivotFractionX = if (handler.swipeEdge == BackEventCompat.EDGE_LEFT) 0.8f else 0.2f,
-                                pivotFractionY = 0.5f,
-                            )
-                            this.scaleX = handler.scale
-                            this.scaleY = handler.scale
-                            this.translationY = handler.translationY
-                            this.clip = true
-                            this.shape = if (showPrev) {
-                                RoundedCornerShape(handler.windowCornerRadius.toFloat())
-                            } else {
-                                RectangleShape
-                            }
-                        }
-                        .then(
-                            if (showPrev) {
-                                Modifier.pointerInput(Unit) {
-                                    // Animated content should not be interactive
-                                }
-                            } else {
-                                Modifier
-                            },
-                        ),
-                    content = {
-                        if (visibleItems.size == 2 && visibleItems.getOrNull(1) == it) {
-                            // Avoid drawing previous screen
-                            return@AnimatedContent
-                        }
-                        screenContent(it)
-                    },
-                )
-            } else {
-                Box(
-                    modifier = Modifier
-                        .zIndex(0f)
-                        .drawWithCache {
-                            val bounds = Rect(Offset.Zero, size)
-                            val matrix = ColorMatrix().apply {
-                                // Reduce saturation and brightness
-                                setToSaturation(lerp(1f, 0.95f, handler.alpha))
-                                set(0, 4, lerp(0f, -25f, handler.alpha))
-                                set(1, 4, lerp(0f, -25f, handler.alpha))
-                                set(2, 4, lerp(0f, -25f, handler.alpha))
-                            }
-                            val paint = Paint().apply { colorFilter = ColorFilter.colorMatrix(matrix) }
-                            onDrawWithContent {
-                                drawIntoCanvas {
-                                    it.saveLayer(bounds, paint)
-                                    drawContent()
-                                    it.restore()
-                                }
-                            }
-                        }
-                        .graphicsLayer {
-                            val blurRadius = 5.dp.toPx() * handler.alpha
-                            renderEffect = if (blurRadius > 0f) {
-                                BlurEffect(blurRadius, blurRadius)
-                            } else {
-                                null
-                            }
-                        }
-                        .pointerInput(Unit) {
-                            // bg content should not be interactive
-                        },
-                    content = { screenContent(backStackEntry) },
-                )
-            }
-        }
-
-        LaunchedEffect(currentSceneEntry) {
-            // Reset *after* the screen is popped successfully
-            // so that the correct transition is applied
-            handler.setReady()
-        }
-    }
-}
-
-@Stable
-private class OnBackHandler(
-    private val scope: CoroutineScope,
-    val windowCornerRadius: Int,
-    private val onBackPressed: () -> Unit,
-) {
-
-    var isReady = true
-        private set
-
-    var alpha by mutableFloatStateOf(1f)
-        private set
-
-    var scale by mutableFloatStateOf(1f)
-        private set
-
-    var translationY by mutableFloatStateOf(0f)
-        private set
-
-    var swipeEdge by mutableIntStateOf(BackEventCompat.EDGE_LEFT)
-        private set
-
-    private var containerSize = Size.Zero
-    private var startPointY = Float.NaN
-
-    var isPredictiveBack by mutableStateOf(false)
-        private set
-
-    private var animationJob: Job? = null
-        set(value) {
-            isReady = false
-            field = value
-        }
-
-    fun updateContainerSize(size: Size) {
-        containerSize = size
-    }
-
-    fun setReady() {
-        reset()
-        animationJob?.cancel()
-        animationJob = null
-        isReady = true
-        isPredictiveBack = false
-    }
-
-    fun reset() {
-        startPointY = Float.NaN
-    }
-
-    fun onBackEvent(backEvent: BackEventCompat) {
-        if (!isReady) return
-        isPredictiveBack = true
-        swipeEdge = backEvent.swipeEdge
-
-        val progress = LinearOutSlowInEasing.transform(backEvent.progress)
-        scale = lerp(1f, 0.85f, progress)
-
-        if (startPointY.isNaN()) {
-            startPointY = backEvent.touchY
-        }
-        val deltaYRatio = (backEvent.touchY - startPointY) / containerSize.height
-        val translateYDistance = containerSize.height / 20
-        translationY = sin(deltaYRatio * PI * 0.5).toFloat() * translateYDistance * progress
-    }
-
-    fun onBackConfirmed() {
-        if (!isReady) return
-        if (isPredictiveBack) {
-            // Continue predictive animation and pop the screen
-            val animationSpec = tween<Float>(
-                durationMillis = MotionConstants.DefaultMotionDuration,
-                easing = FastOutSlowInEasing,
+fun DefaultNavigatorScreenTransition(navigator: Navigator) {
+    val slideDistance = rememberSlideDistance()
+    ScreenTransition(
+        navigator = navigator,
+        transition = {
+            materialSharedAxisX(
+                forward = navigator.lastEvent != StackEvent.Pop,
+                slideDistance = slideDistance,
             )
-            animationJob = scope.launch {
-                try {
-                    listOf(
-                        async {
-                            animate(
-                                initialValue = alpha,
-                                targetValue = 0f,
-                                animationSpec = animationSpec,
-                            ) { value, _ ->
-                                alpha = value
-                            }
-                        },
-                        async {
-                            animate(
-                                initialValue = scale,
-                                targetValue = scale - 0.05f,
-                                animationSpec = animationSpec,
-                            ) { value, _ ->
-                                scale = value
-                            }
-                        },
-                    ).awaitAll()
-                } catch (e: CancellationException) {
-                    // no-op
-                } finally {
-                    onBackPressed()
-                    alpha = 1f
-                    translationY = 0f
-                    scale = 1f
-                }
-            }
-        } else {
-            // Pop right away and use default transition
-            onBackPressed()
-        }
-    }
-
-    fun onBackCancelled() {
-        // Reset states
-        isPredictiveBack = false
-        animationJob = scope.launch {
-            listOf(
-                async {
-                    animate(
-                        initialValue = scale,
-                        targetValue = 1f,
-                    ) { value, _ ->
-                        scale = value
-                    }
-                },
-                async {
-                    animate(
-                        initialValue = alpha,
-                        targetValue = 1f,
-                    ) { value, _ ->
-                        alpha = value
-                    }
-                },
-                async {
-                    animate(
-                        initialValue = translationY,
-                        targetValue = 0f,
-                    ) { value, _ ->
-                        translationY = value
-                    }
-                },
-            ).awaitAll()
-
-            isReady = true
-        }
-    }
+        },
+    )
 }
 
 @Composable

+ 5 - 44
app/src/main/java/eu/kanade/tachiyomi/ui/home/HomeScreen.kt

@@ -1,11 +1,8 @@
 package eu.kanade.tachiyomi.ui.home
 
-import androidx.activity.compose.PredictiveBackHandler
+import androidx.activity.compose.BackHandler
 import androidx.compose.animation.AnimatedContent
 import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.core.LinearOutSlowInEasing
-import androidx.compose.animation.core.animate
-import androidx.compose.animation.core.tween
 import androidx.compose.animation.expandVertically
 import androidx.compose.animation.shrinkVertically
 import androidx.compose.animation.togetherWith
@@ -26,20 +23,13 @@ import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.produceState
-import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.TransformOrigin
-import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.util.fastForEach
-import androidx.compose.ui.util.lerp
 import cafe.adriel.voyager.navigator.LocalNavigator
 import cafe.adriel.voyager.navigator.currentOrThrow
 import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
@@ -59,7 +49,6 @@ import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.receiveAsFlow
 import kotlinx.coroutines.launch
-import soup.compose.material.motion.MotionConstants
 import soup.compose.material.motion.animation.materialFadeThroughIn
 import soup.compose.material.motion.animation.materialFadeThroughOut
 import tachiyomi.domain.library.service.LibraryPreferences
@@ -70,7 +59,6 @@ import tachiyomi.presentation.core.components.material.Scaffold
 import tachiyomi.presentation.core.i18n.pluralStringResource
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
-import kotlin.coroutines.cancellation.CancellationException
 
 object HomeScreen : Screen() {
 
@@ -92,8 +80,6 @@ object HomeScreen : Screen() {
     @Composable
     override fun Content() {
         val navigator = LocalNavigator.currentOrThrow
-        var scale by remember { mutableFloatStateOf(1f) }
-
         TabNavigator(
             tab = LibraryTab,
             key = TabNavigatorKey,
@@ -132,11 +118,6 @@ object HomeScreen : Screen() {
                 ) { contentPadding ->
                     Box(
                         modifier = Modifier
-                            .graphicsLayer {
-                                scaleX = scale
-                                scaleY = scale
-                                transformOrigin = TransformOrigin(0.5f, 1f)
-                            }
                             .padding(contentPadding)
                             .consumeWindowInsets(contentPadding),
                     ) {
@@ -157,30 +138,10 @@ object HomeScreen : Screen() {
             }
 
             val goToLibraryTab = { tabNavigator.current = LibraryTab }
-
-            var handlingBack by remember { mutableStateOf(false) }
-            PredictiveBackHandler(enabled = handlingBack || tabNavigator.current != LibraryTab) { progress ->
-                handlingBack = true
-                val currentTab = tabNavigator.current
-                try {
-                    progress.collect { backEvent ->
-                        scale = lerp(1f, 0.92f, LinearOutSlowInEasing.transform(backEvent.progress))
-                        tabNavigator.current = if (backEvent.progress > 0.25f) tabs[0] else currentTab
-                    }
-                    goToLibraryTab()
-                } catch (e: CancellationException) {
-                    tabNavigator.current = currentTab
-                } finally {
-                    animate(
-                        initialValue = scale,
-                        targetValue = 1f,
-                        animationSpec = tween(durationMillis = MotionConstants.DefaultMotionDuration),
-                    ) { value, _ ->
-                        scale = value
-                    }
-                    handlingBack = false
-                }
-            }
+            BackHandler(
+                enabled = tabNavigator.current != LibraryTab,
+                onBack = goToLibraryTab,
+            )
 
             LaunchedEffect(Unit) {
                 launch {

+ 6 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -11,6 +11,7 @@ import android.os.Bundle
 import android.view.View
 import androidx.activity.ComponentActivity
 import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.WindowInsetsSides
 import androidx.compose.foundation.layout.consumeWindowInsets
@@ -222,13 +223,14 @@ class MainActivity : BaseActivity() {
                     contentWindowInsets = scaffoldInsets,
                 ) { contentPadding ->
                     // Consume insets already used by app state banners
-                    // Shows current screen
-                    DefaultNavigatorScreenTransition(
-                        navigator = navigator,
+                    Box(
                         modifier = Modifier
                             .padding(contentPadding)
                             .consumeWindowInsets(contentPadding),
-                    )
+                    ) {
+                        // Shows current screen
+                        DefaultNavigatorScreenTransition(navigator = navigator)
+                    }
                 }
 
                 // Pop source-related screens when incognito mode is turned off

+ 0 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsScreen.kt

@@ -40,7 +40,6 @@ class SettingsScreen(
                     Destination.Tracking.id -> SettingsTrackingScreen
                     else -> SettingsMainScreen
                 },
-                onBackPressed = null,
                 content = {
                     val pop: () -> Unit = {
                         if (it.canPop) {
@@ -62,7 +61,6 @@ class SettingsScreen(
                     Destination.Tracking.id -> SettingsTrackingScreen
                     else -> SettingsAppearanceScreen
                 },
-                onBackPressed = null,
             ) {
                 val insets = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal)
                 TwoPanelBox(

+ 0 - 21
app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt

@@ -4,11 +4,9 @@ package eu.kanade.tachiyomi.util.view
 
 import android.content.res.Resources
 import android.graphics.Rect
-import android.os.Build
 import android.view.Gravity
 import android.view.Menu
 import android.view.MenuItem
-import android.view.RoundedCorner
 import android.view.View
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
@@ -97,22 +95,3 @@ fun View?.isVisibleOnScreen(): Boolean {
         Rect(0, 0, Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels)
     return actualPosition.intersect(screen)
 }
-
-/**
- * Returns window radius (in pixel) applied to this view
- */
-fun View.getWindowRadius(): Int {
-    val rad = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
-        val windowInsets = rootWindowInsets
-        listOfNotNull(
-            windowInsets.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT),
-            windowInsets.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT),
-            windowInsets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT),
-            windowInsets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT),
-        )
-            .minOfOrNull { it.radius }
-    } else {
-        null
-    }
-    return rad ?: 0
-}

+ 8 - 55
presentation-core/src/main/java/tachiyomi/presentation/core/components/AdaptiveSheet.kt

@@ -1,11 +1,7 @@
 package tachiyomi.presentation.core.components
 
-import androidx.activity.compose.PredictiveBackHandler
-import androidx.compose.animation.core.LinearOutSlowInEasing
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.animate
+import androidx.activity.compose.BackHandler
 import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.gestures.AnchoredDraggableState
@@ -30,7 +26,6 @@ import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.remember
@@ -39,11 +34,8 @@ import androidx.compose.runtime.setValue
 import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
 import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.TransformOrigin
-import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -53,14 +45,14 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.lerp
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.drop
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.launch
-import kotlin.coroutines.cancellation.CancellationException
 import kotlin.math.roundToInt
 
+private val sheetAnimationSpec = tween<Float>(durationMillis = 350)
+
 @Composable
 fun AdaptiveSheet(
     isTabletUi: Boolean,
@@ -99,11 +91,6 @@ fun AdaptiveSheet(
         ) {
             Surface(
                 modifier = Modifier
-                    .predictiveBackAnimation(
-                        enabled = remember { derivedStateOf { alpha > 0f } }.value,
-                        transformOrigin = TransformOrigin.Center,
-                        onBack = internalOnDismissRequest,
-                    )
                     .requiredWidthIn(max = 460.dp)
                     .clickable(
                         interactionSource = remember { MutableInteractionSource() },
@@ -116,6 +103,7 @@ fun AdaptiveSheet(
                 shape = MaterialTheme.shapes.extraLarge,
                 tonalElevation = tonalElevation,
                 content = {
+                    BackHandler(enabled = alpha > 0f, onBack = internalOnDismissRequest)
                     content()
                 },
             )
@@ -157,11 +145,6 @@ fun AdaptiveSheet(
         ) {
             Surface(
                 modifier = Modifier
-                    .predictiveBackAnimation(
-                        enabled = anchoredDraggableState.targetValue == 0,
-                        transformOrigin = TransformOrigin(0.5f, 1f),
-                        onBack = internalOnDismissRequest,
-                    )
                     .widthIn(max = 460.dp)
                     .clickable(
                         interactionSource = remember { MutableInteractionSource() },
@@ -201,6 +184,10 @@ fun AdaptiveSheet(
                 shape = MaterialTheme.shapes.extraLarge,
                 tonalElevation = tonalElevation,
                 content = {
+                    BackHandler(
+                        enabled = anchoredDraggableState.targetValue == 0,
+                        onBack = internalOnDismissRequest,
+                    )
                     content()
                 },
             )
@@ -270,37 +257,3 @@ private fun <T> AnchoredDraggableState<T>.preUpPostDownNestedScrollConnection()
         @JvmName("offsetToFloat")
         private fun Offset.toFloat(): Float = this.y
     }
-
-private fun Modifier.predictiveBackAnimation(
-    enabled: Boolean,
-    transformOrigin: TransformOrigin,
-    onBack: () -> Unit,
-) = composed {
-    var scale by remember { mutableFloatStateOf(1f) }
-    PredictiveBackHandler(enabled = enabled) { progress ->
-        try {
-            progress.collect { backEvent ->
-                scale = lerp(1f, 0.85f, LinearOutSlowInEasing.transform(backEvent.progress))
-            }
-            // Completion
-            onBack()
-        } catch (e: CancellationException) {
-            // Cancellation
-        } finally {
-            animate(
-                initialValue = scale,
-                targetValue = 1f,
-                animationSpec = spring(stiffness = Spring.StiffnessLow),
-            ) { value, _ ->
-                scale = value
-            }
-        }
-    }
-    Modifier.graphicsLayer {
-        this.scaleX = scale
-        this.scaleY = scale
-        this.transformOrigin = transformOrigin
-    }
-}
-
-private val sheetAnimationSpec = tween<Float>(durationMillis = 350)