|
@@ -1,14 +1,14 @@
|
|
|
/*
|
|
/*
|
|
|
* Copyright (c) Milan Jurkulák 2023.
|
|
* Copyright (c) Milan Jurkulák 2023.
|
|
|
- * Contact:
|
|
|
|
|
- * e: mimoccc@gmail.com
|
|
|
|
|
- * e: mj@mjdev.org
|
|
|
|
|
- * w: https://mjdev.org
|
|
|
|
|
|
|
+ * Contact:
|
|
|
|
|
+ * e: mimoccc@gmail.com
|
|
|
|
|
+ * e: mj@mjdev.org
|
|
|
|
|
+ * w: https://mjdev.org
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
@file:Suppress("MemberVisibilityCanBePrivate")
|
|
@file:Suppress("MemberVisibilityCanBePrivate")
|
|
|
|
|
|
|
|
-package org.mjdev.tvapp.base.navigation
|
|
|
|
|
|
|
+package org.mjdev.tvapp.base.ui.components.navigation
|
|
|
|
|
|
|
|
import android.os.Bundle
|
|
import android.os.Bundle
|
|
|
import androidx.annotation.CallSuper
|
|
import androidx.annotation.CallSuper
|
|
@@ -16,9 +16,6 @@ import androidx.annotation.MainThread
|
|
|
import androidx.compose.animation.AnimatedContentTransitionScope
|
|
import androidx.compose.animation.AnimatedContentTransitionScope
|
|
|
import androidx.compose.animation.EnterTransition
|
|
import androidx.compose.animation.EnterTransition
|
|
|
import androidx.compose.animation.ExitTransition
|
|
import androidx.compose.animation.ExitTransition
|
|
|
-import androidx.compose.animation.core.tween
|
|
|
|
|
-import androidx.compose.animation.slideInVertically
|
|
|
|
|
-import androidx.compose.animation.slideOutVertically
|
|
|
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.background
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
|
import androidx.compose.foundation.layout.Column
|
|
import androidx.compose.foundation.layout.Column
|
|
@@ -43,17 +40,11 @@ import androidx.navigation.NavHostController
|
|
|
import androidx.navigation.compose.composable
|
|
import androidx.navigation.compose.composable
|
|
|
import androidx.tv.material3.Text
|
|
import androidx.tv.material3.Text
|
|
|
import org.mjdev.tvapp.base.annotations.TvPreview
|
|
import org.mjdev.tvapp.base.annotations.TvPreview
|
|
|
|
|
+import org.mjdev.tvapp.base.extensions.AnimExt.FadeIn
|
|
|
|
|
+import org.mjdev.tvapp.base.extensions.AnimExt.FadeOut
|
|
|
|
|
+import org.mjdev.tvapp.base.extensions.NavExt.rememberNavControllerEx
|
|
|
import kotlin.reflect.full.createInstance
|
|
import kotlin.reflect.full.createInstance
|
|
|
|
|
|
|
|
-/**
|
|
|
|
|
- * Screen class.
|
|
|
|
|
- *
|
|
|
|
|
- * This is base of all screens in application and auto creation of route and nav graph.
|
|
|
|
|
- * This object represents one screen at time.
|
|
|
|
|
- * Can contain menu that is exported to navigation drawer.
|
|
|
|
|
- *
|
|
|
|
|
- * @constructor Create empty constructor for screen
|
|
|
|
|
- */
|
|
|
|
|
@Suppress("unused", "LeakingThis")
|
|
@Suppress("unused", "LeakingThis")
|
|
|
open class Screen : NavController.OnDestinationChangedListener {
|
|
open class Screen : NavController.OnDestinationChangedListener {
|
|
|
|
|
|
|
@@ -69,45 +60,59 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
routeImpl
|
|
routeImpl
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- open val titleResId: Int = -1
|
|
|
|
|
-
|
|
|
|
|
open val args: List<NamedNavArgument> = emptyList()
|
|
open val args: List<NamedNavArgument> = emptyList()
|
|
|
|
|
|
|
|
- open val menuTitleResId: Int = -1
|
|
|
|
|
|
|
+ open val title: Any? = null
|
|
|
|
|
+
|
|
|
|
|
+ open val menuTitle: Any? = null
|
|
|
|
|
|
|
|
open val menuIcon: ImageVector? = null
|
|
open val menuIcon: ImageVector? = null
|
|
|
|
|
|
|
|
- open val showOnce = false
|
|
|
|
|
|
|
+ open val backgroundColor: Color = Color.DarkGray
|
|
|
|
|
|
|
|
- open val backgroundColor :Color = Color.DarkGray
|
|
|
|
|
|
|
+ open val roundRadius: Dp = 0.dp
|
|
|
|
|
|
|
|
- open val roundRadius : Dp = 0.dp
|
|
|
|
|
|
|
+ open val background: Shape = RoundedCornerShape(roundRadius)
|
|
|
|
|
|
|
|
- open val background : Shape = RoundedCornerShape(roundRadius)
|
|
|
|
|
|
|
+ open val showOnce = false
|
|
|
|
|
+
|
|
|
|
|
+ open val immersive: Boolean = false
|
|
|
|
|
|
|
|
val menuItem
|
|
val menuItem
|
|
|
- get() = if (menuTitleResId >= 0) MenuItem(menuTitleResId, menuIcon, completeRoute)
|
|
|
|
|
- else null
|
|
|
|
|
|
|
+ get() = if (menuTitle != null) MenuItem(
|
|
|
|
|
+ menuText = menuTitle,
|
|
|
|
|
+ menuIcon = menuIcon,
|
|
|
|
|
+ menuRoute = completeRoute
|
|
|
|
|
+ ) else null
|
|
|
|
|
|
|
|
@TvPreview
|
|
@TvPreview
|
|
|
@Composable
|
|
@Composable
|
|
|
@CallSuper
|
|
@CallSuper
|
|
|
open fun Compose() {
|
|
open fun Compose() {
|
|
|
- Compose(null, null, emptyList(), mapOf())
|
|
|
|
|
|
|
+
|
|
|
|
|
+ val navController = rememberNavControllerEx()
|
|
|
|
|
+
|
|
|
|
|
+ Compose(
|
|
|
|
|
+ navController,
|
|
|
|
|
+ null,
|
|
|
|
|
+ mapOf()
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
@Composable
|
|
|
open fun Compose(
|
|
open fun Compose(
|
|
|
- navController: NavHostControllerEx?,
|
|
|
|
|
|
|
+ navController: NavHostControllerEx,
|
|
|
backStackEntry: NavBackStackEntry?,
|
|
backStackEntry: NavBackStackEntry?,
|
|
|
- menuItems: List<MenuItem>,
|
|
|
|
|
args: Map<String, Any?>
|
|
args: Map<String, Any?>
|
|
|
) {
|
|
) {
|
|
|
|
|
|
|
|
if (showOnce) {
|
|
if (showOnce) {
|
|
|
- navController?.addOnDestinationChangedListener(this)
|
|
|
|
|
|
|
+ navController.addOnDestinationChangedListener(this)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ navController.menuState.value = !immersive
|
|
|
|
|
+
|
|
|
Column(
|
|
Column(
|
|
|
modifier = Modifier
|
|
modifier = Modifier
|
|
|
.fillMaxSize()
|
|
.fillMaxSize()
|
|
@@ -115,14 +120,12 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
verticalArrangement = Arrangement.Center,
|
|
verticalArrangement = Arrangement.Center,
|
|
|
horizontalAlignment = Alignment.CenterHorizontally
|
|
horizontalAlignment = Alignment.CenterHorizontally
|
|
|
) {
|
|
) {
|
|
|
-
|
|
|
|
|
Text(
|
|
Text(
|
|
|
text = "Empty Screen",
|
|
text = "Empty Screen",
|
|
|
fontSize = 64.sp,
|
|
fontSize = 64.sp,
|
|
|
fontWeight = FontWeight.Bold,
|
|
fontWeight = FontWeight.Bold,
|
|
|
color = Color.White
|
|
color = Color.White
|
|
|
)
|
|
)
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
@@ -139,9 +142,6 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
|
|
|
|
|
companion object {
|
|
companion object {
|
|
|
|
|
|
|
|
- val SlideInVertically = slideInVertically(animationSpec = tween(1000))
|
|
|
|
|
- val SlideOutVertically = slideOutVertically(animationSpec = tween(1000))
|
|
|
|
|
-
|
|
|
|
|
@Suppress("UNCHECKED_CAST", "DEPRECATION")
|
|
@Suppress("UNCHECKED_CAST", "DEPRECATION")
|
|
|
private fun <T> NavBackStackEntry.arg(
|
|
private fun <T> NavBackStackEntry.arg(
|
|
|
argId: String,
|
|
argId: String,
|
|
@@ -149,34 +149,20 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
): T = (arguments?.get(argId) as? T?) ?: defaultValue
|
|
): T = (arguments?.get(argId) as? T?) ?: defaultValue
|
|
|
|
|
|
|
|
@MainThread
|
|
@MainThread
|
|
|
- inline fun <reified T : Screen> NavHostController.open(
|
|
|
|
|
- vararg values: Any?
|
|
|
|
|
|
|
+ fun NavHostController.open(
|
|
|
|
|
+ route: String?
|
|
|
) {
|
|
) {
|
|
|
- val instance = T::class.createInstance()
|
|
|
|
|
- instance.completeRoute.let { r ->
|
|
|
|
|
- var routeImpl = r
|
|
|
|
|
- instance.args.forEachIndexed { idx, arg ->
|
|
|
|
|
- routeImpl = routeImpl.replace(
|
|
|
|
|
- "{${arg.name}}",
|
|
|
|
|
- (values[idx] ?: "").toString()
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- routeImpl
|
|
|
|
|
- }.also { finalRoute ->
|
|
|
|
|
|
|
+ if (route != null) {
|
|
|
val currentRoute = currentRoute
|
|
val currentRoute = currentRoute
|
|
|
- val equals = currentRoute?.equals(finalRoute)
|
|
|
|
|
|
|
+ val equals = currentRoute?.equals(route)
|
|
|
if (equals != true) {
|
|
if (equals != true) {
|
|
|
-// try {
|
|
|
|
|
- navigate(finalRoute)
|
|
|
|
|
-// } catch (e: Exception) {
|
|
|
|
|
-// Timber.e(e)
|
|
|
|
|
-// }
|
|
|
|
|
|
|
+ navigate(route)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@MainThread
|
|
@MainThread
|
|
|
- inline fun <reified T : Screen> NavHostController.openClear(
|
|
|
|
|
|
|
+ inline fun <reified T : Screen> NavHostController.open(
|
|
|
vararg values: Any?
|
|
vararg values: Any?
|
|
|
) {
|
|
) {
|
|
|
val instance = T::class.createInstance()
|
|
val instance = T::class.createInstance()
|
|
@@ -193,11 +179,7 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
val currentRoute = currentRoute
|
|
val currentRoute = currentRoute
|
|
|
val equals = currentRoute?.equals(finalRoute)
|
|
val equals = currentRoute?.equals(finalRoute)
|
|
|
if (equals != true) {
|
|
if (equals != true) {
|
|
|
-// try {
|
|
|
|
|
- navigate(finalRoute)
|
|
|
|
|
-// } catch (e: Exception) {
|
|
|
|
|
-// Timber.e(e)
|
|
|
|
|
-// }
|
|
|
|
|
|
|
+ navigate(finalRoute)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -212,11 +194,11 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
deepLinks: List<NavDeepLink> = emptyList(),
|
|
deepLinks: List<NavDeepLink> = emptyList(),
|
|
|
enterTransition: (@JvmSuppressWildcards
|
|
enterTransition: (@JvmSuppressWildcards
|
|
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? = {
|
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? = {
|
|
|
- SlideInVertically
|
|
|
|
|
|
|
+ FadeIn
|
|
|
},
|
|
},
|
|
|
exitTransition: (@JvmSuppressWildcards
|
|
exitTransition: (@JvmSuppressWildcards
|
|
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? = {
|
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? = {
|
|
|
- SlideOutVertically
|
|
|
|
|
|
|
+ FadeOut
|
|
|
},
|
|
},
|
|
|
popEnterTransition: (@JvmSuppressWildcards
|
|
popEnterTransition: (@JvmSuppressWildcards
|
|
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? =
|
|
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? =
|
|
@@ -232,7 +214,7 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
homeDestinationRoute = route.completeRoute
|
|
homeDestinationRoute = route.completeRoute
|
|
|
}
|
|
}
|
|
|
route.menuItem?.also { menuItem ->
|
|
route.menuItem?.also { menuItem ->
|
|
|
- menuItems.add(menuItem)
|
|
|
|
|
|
|
+ navHostController.addMenuItem(menuItem)
|
|
|
}
|
|
}
|
|
|
composable(
|
|
composable(
|
|
|
route = route.completeRoute,
|
|
route = route.completeRoute,
|
|
@@ -248,7 +230,7 @@ open class Screen : NavController.OnDestinationChangedListener {
|
|
|
put(arg.name, be.arg(arg.name, null))
|
|
put(arg.name, be.arg(arg.name, null))
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- route.Compose(navHostController, be, menuItems, rArgs)
|
|
|
|
|
|
|
+ route.Compose(navHostController, be, rArgs)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|