feat(ui): predictive back animation for Android 14+
This commit is contained in:
parent
c691a106d5
commit
2655cb5f43
@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
android:maxSdkVersion="28" />
|
android:maxSdkVersion="28" />
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -19,6 +21,7 @@
|
|||||||
<application
|
<application
|
||||||
android:name=".infrastructure.android.AndroidApp"
|
android:name=".infrastructure.android.AndroidApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/read_you"
|
android:label="@string/read_you"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
@ -8,38 +8,88 @@
|
|||||||
|
|
||||||
package me.ash.reader.ui.ext
|
package me.ash.reader.ui.ext
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.navigation.NamedNavArgument
|
import androidx.navigation.NamedNavArgument
|
||||||
import androidx.navigation.NavBackStackEntry
|
import androidx.navigation.NavBackStackEntry
|
||||||
import androidx.navigation.NavDeepLink
|
import androidx.navigation.NavDeepLink
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
|
import me.ash.reader.ui.motion.EmphasizedAccelerate
|
||||||
|
import me.ash.reader.ui.motion.EmphasizedDecelerate
|
||||||
import me.ash.reader.ui.motion.materialSharedAxisXIn
|
import me.ash.reader.ui.motion.materialSharedAxisXIn
|
||||||
import me.ash.reader.ui.motion.materialSharedAxisXOut
|
import me.ash.reader.ui.motion.materialSharedAxisXOut
|
||||||
|
|
||||||
private const val INITIAL_OFFSET_FACTOR = 0.10f
|
private const val INITIAL_OFFSET_FACTOR = 0.10f
|
||||||
|
private const val INITIAL_SCALE_FACTOR = 0.8f
|
||||||
|
|
||||||
|
|
||||||
fun NavGraphBuilder.animatedComposable(
|
fun NavGraphBuilder.animatedComposable(
|
||||||
route: String,
|
route: String,
|
||||||
arguments: List<NamedNavArgument> = emptyList(),
|
arguments: List<NamedNavArgument> = emptyList(),
|
||||||
deepLinks: List<NavDeepLink> = emptyList(),
|
deepLinks: List<NavDeepLink> = emptyList(),
|
||||||
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit
|
usePredictiveBack: Boolean = Build.VERSION.SDK_INT >= 34,
|
||||||
) = composable(
|
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit,
|
||||||
|
) {
|
||||||
|
if (usePredictiveBack) {
|
||||||
|
animatedComposablePredictiveBack(route, arguments, deepLinks, content)
|
||||||
|
} else {
|
||||||
|
animatedComposableLegacy(route, arguments, deepLinks, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun NavGraphBuilder.animatedComposablePredictiveBack(
|
||||||
|
route: String,
|
||||||
|
arguments: List<NamedNavArgument> = emptyList(),
|
||||||
|
deepLinks: List<NavDeepLink> = emptyList(),
|
||||||
|
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit,
|
||||||
|
) =
|
||||||
|
composable(
|
||||||
route = route,
|
route = route,
|
||||||
arguments = arguments,
|
arguments = arguments,
|
||||||
deepLinks = deepLinks,
|
deepLinks = deepLinks,
|
||||||
enterTransition = {
|
enterTransition = { materialSharedAxisXIn(initialOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }) },
|
||||||
materialSharedAxisXIn(initialOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() })
|
|
||||||
},
|
|
||||||
exitTransition = {
|
exitTransition = {
|
||||||
materialSharedAxisXOut(targetOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
|
materialSharedAxisXOut(targetOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
|
||||||
},
|
},
|
||||||
popEnterTransition = {
|
popEnterTransition = {
|
||||||
materialSharedAxisXIn(initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
|
scaleIn(
|
||||||
|
animationSpec = tween(durationMillis = 350, easing = EmphasizedDecelerate),
|
||||||
|
initialScale = INITIAL_SCALE_FACTOR,
|
||||||
|
) + materialSharedAxisXIn(initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
|
||||||
},
|
},
|
||||||
popExitTransition = {
|
popExitTransition = {
|
||||||
materialSharedAxisXOut(targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() })
|
materialSharedAxisXOut(targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }) +
|
||||||
|
scaleOut(
|
||||||
|
targetScale = INITIAL_SCALE_FACTOR,
|
||||||
|
animationSpec = tween(durationMillis = 350, easing = EmphasizedAccelerate),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
content = content
|
content = content,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun NavGraphBuilder.animatedComposableLegacy(
|
||||||
|
route: String,
|
||||||
|
arguments: List<NamedNavArgument> = emptyList(),
|
||||||
|
deepLinks: List<NavDeepLink> = emptyList(),
|
||||||
|
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit
|
||||||
|
) = composable(
|
||||||
|
route = route,
|
||||||
|
arguments = arguments,
|
||||||
|
deepLinks = deepLinks,
|
||||||
|
enterTransition = {
|
||||||
|
materialSharedAxisXIn(initialOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() })
|
||||||
|
},
|
||||||
|
exitTransition = {
|
||||||
|
materialSharedAxisXOut(targetOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
|
||||||
|
},
|
||||||
|
popEnterTransition = {
|
||||||
|
materialSharedAxisXIn(initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
|
||||||
|
},
|
||||||
|
popExitTransition = {
|
||||||
|
materialSharedAxisXOut(targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() })
|
||||||
|
},
|
||||||
|
content = content
|
||||||
)
|
)
|
||||||
|
@ -204,9 +204,6 @@ fun FeedsPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BackHandler(true) {
|
|
||||||
context.findActivity()?.moveTaskToBack(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
RYScaffold(
|
RYScaffold(
|
||||||
topBarTonalElevation = topBarTonalElevation.value.dp,
|
topBarTonalElevation = topBarTonalElevation.value.dp,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user