Navigator.kt 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package eu.kanade.presentation.util
  2. import androidx.compose.animation.AnimatedContent
  3. import androidx.compose.animation.AnimatedContentTransitionScope
  4. import androidx.compose.animation.ContentTransform
  5. import androidx.compose.runtime.Composable
  6. import androidx.compose.runtime.ProvidableCompositionLocal
  7. import androidx.compose.runtime.staticCompositionLocalOf
  8. import androidx.compose.ui.Modifier
  9. import cafe.adriel.voyager.core.model.ScreenModel
  10. import cafe.adriel.voyager.core.model.ScreenModelStore
  11. import cafe.adriel.voyager.core.screen.Screen
  12. import cafe.adriel.voyager.core.screen.ScreenKey
  13. import cafe.adriel.voyager.core.screen.uniqueScreenKey
  14. import cafe.adriel.voyager.core.stack.StackEvent
  15. import cafe.adriel.voyager.navigator.Navigator
  16. import cafe.adriel.voyager.transitions.ScreenTransitionContent
  17. import kotlinx.coroutines.CoroutineName
  18. import kotlinx.coroutines.CoroutineScope
  19. import kotlinx.coroutines.Dispatchers
  20. import kotlinx.coroutines.SupervisorJob
  21. import kotlinx.coroutines.cancel
  22. import kotlinx.coroutines.plus
  23. import soup.compose.material.motion.animation.materialSharedAxisX
  24. import soup.compose.material.motion.animation.rememberSlideDistance
  25. /**
  26. * For invoking back press to the parent activity
  27. */
  28. val LocalBackPress: ProvidableCompositionLocal<(() -> Unit)?> = staticCompositionLocalOf { null }
  29. interface Tab : cafe.adriel.voyager.navigator.tab.Tab {
  30. suspend fun onReselect(navigator: Navigator) {}
  31. }
  32. abstract class Screen : Screen {
  33. override val key: ScreenKey = uniqueScreenKey
  34. }
  35. /**
  36. * A variant of ScreenModel.coroutineScope except with the IO dispatcher instead of the
  37. * main dispatcher.
  38. */
  39. val ScreenModel.ioCoroutineScope: CoroutineScope
  40. get() = ScreenModelStore.getOrPutDependency(
  41. screenModel = this,
  42. name = "ScreenModelIoCoroutineScope",
  43. factory = { key -> CoroutineScope(Dispatchers.IO + SupervisorJob()) + CoroutineName(key) },
  44. onDispose = { scope -> scope.cancel() },
  45. )
  46. interface AssistContentScreen {
  47. fun onProvideAssistUrl(): String?
  48. }
  49. @Composable
  50. fun DefaultNavigatorScreenTransition(navigator: Navigator) {
  51. val slideDistance = rememberSlideDistance()
  52. ScreenTransition(
  53. navigator = navigator,
  54. transition = {
  55. materialSharedAxisX(
  56. forward = navigator.lastEvent != StackEvent.Pop,
  57. slideDistance = slideDistance,
  58. )
  59. },
  60. )
  61. }
  62. @Composable
  63. fun ScreenTransition(
  64. navigator: Navigator,
  65. transition: AnimatedContentTransitionScope<Screen>.() -> ContentTransform,
  66. modifier: Modifier = Modifier,
  67. content: ScreenTransitionContent = { it.Content() },
  68. ) {
  69. AnimatedContent(
  70. targetState = navigator.lastItem,
  71. transitionSpec = transition,
  72. modifier = modifier,
  73. label = "ScreenTransition",
  74. ) { screen ->
  75. navigator.saveableState("transition", screen) {
  76. content(screen)
  77. }
  78. }
  79. }