Routes.kt (7107B) - raw


      1 package me.rhunk.snapenhance.ui.manager
      2 
      3 import androidx.compose.foundation.layout.RowScope
      4 import androidx.compose.material.icons.Icons
      5 import androidx.compose.material.icons.filled.*
      6 import androidx.compose.runtime.Composable
      7 import androidx.compose.ui.graphics.vector.ImageVector
      8 import androidx.navigation.NavBackStackEntry
      9 import androidx.navigation.NavController
     10 import androidx.navigation.NavDestination.Companion.hierarchy
     11 import androidx.navigation.NavGraph.Companion.findStartDestination
     12 import androidx.navigation.NavGraphBuilder
     13 import me.rhunk.snapenhance.RemoteSideContext
     14 import me.rhunk.snapenhance.ui.manager.pages.FileImportsRoot
     15 import me.rhunk.snapenhance.ui.manager.pages.LoggerHistoryRoot
     16 import me.rhunk.snapenhance.ui.manager.pages.ManageReposSection
     17 import me.rhunk.snapenhance.ui.manager.pages.TasksRootSection
     18 import me.rhunk.snapenhance.ui.manager.pages.features.FeaturesRootSection
     19 import me.rhunk.snapenhance.ui.manager.pages.features.ManageRuleFeature
     20 import me.rhunk.snapenhance.ui.manager.pages.home.HomeLogs
     21 import me.rhunk.snapenhance.ui.manager.pages.home.HomeRootSection
     22 import me.rhunk.snapenhance.ui.manager.pages.home.HomeSettings
     23 import me.rhunk.snapenhance.ui.manager.pages.location.BetterLocationRoot
     24 import me.rhunk.snapenhance.ui.manager.pages.scripting.ScriptingRootSection
     25 import me.rhunk.snapenhance.ui.manager.pages.social.LoggedStories
     26 import me.rhunk.snapenhance.ui.manager.pages.social.ManageScope
     27 import me.rhunk.snapenhance.ui.manager.pages.social.MessagingPreview
     28 import me.rhunk.snapenhance.ui.manager.pages.social.SocialRootSection
     29 import me.rhunk.snapenhance.ui.manager.pages.tracker.EditRule
     30 import me.rhunk.snapenhance.ui.manager.pages.tracker.FriendTrackerManagerRoot
     31 
     32 
     33 data class RouteInfo(
     34     val id: String,
     35     val key: String = id,
     36     val icon: ImageVector = Icons.Default.Home,
     37     val primary: Boolean = false,
     38     val showInNavBar: Boolean = primary,
     39 ) {
     40     var translatedKey: Lazy<String?>? = null
     41     val childIds = mutableListOf<String>()
     42 }
     43 
     44 @Suppress("unused", "MemberVisibilityCanBePrivate")
     45 class Routes(
     46     private val context: RemoteSideContext,
     47 ) {
     48     lateinit var navController: NavController
     49     private val routes = mutableListOf<Route>()
     50 
     51     val tasks = route(RouteInfo("tasks", icon = Icons.Default.TaskAlt, primary = true), TasksRootSection())
     52 
     53     val features = route(RouteInfo("features", icon = Icons.Default.Stars, primary = true), FeaturesRootSection())
     54     val manageRuleFeature = route(RouteInfo("manage_rule_feature/?rule_type={rule_type}"), ManageRuleFeature()).parent(features)
     55 
     56     val home = route(RouteInfo("home", icon = Icons.Default.Home, primary = true), HomeRootSection())
     57     val settings = route(RouteInfo("home_settings"), HomeSettings()).parent(home)
     58     val homeLogs = route(RouteInfo("home_logs"), HomeLogs()).parent(home)
     59     val loggerHistory = route(RouteInfo("logger_history"), LoggerHistoryRoot()).parent(home)
     60     val friendTracker = route(RouteInfo("friend_tracker"), FriendTrackerManagerRoot()).parent(home)
     61     val editRule = route(RouteInfo("edit_rule/?rule_id={rule_id}"), EditRule())
     62 
     63     val fileImports = route(RouteInfo("file_imports"), FileImportsRoot()).parent(home)
     64     val manageRepos = route(RouteInfo("manage_repos"), ManageReposSection())
     65 
     66     val social = route(RouteInfo("social", icon = Icons.Default.Group, primary = true), SocialRootSection())
     67     val manageScope = route(RouteInfo("manage_scope/?scope={scope}&id={id}"), ManageScope()).parent(social)
     68     val messagingPreview = route(RouteInfo("messaging_preview/?scope={scope}&id={id}"), MessagingPreview()).parent(social)
     69     val loggedStories = route(RouteInfo("logged_stories/?id={id}"), LoggedStories()).parent(social)
     70 
     71     val scripting = route(RouteInfo("scripts", icon = Icons.Filled.DataObject, primary = true), ScriptingRootSection())
     72 
     73     val betterLocation = route(RouteInfo("better_location", showInNavBar = false, primary = true), BetterLocationRoot())
     74 
     75     open class Route {
     76         open val init: () -> Unit = { }
     77         open val title: @Composable (() -> Unit)? = null
     78         open val topBarActions: @Composable RowScope.() -> Unit = {}
     79         open val floatingActionButton: @Composable () -> Unit = {}
     80         open val content: @Composable (NavBackStackEntry) -> Unit = {}
     81         open val customComposables: NavGraphBuilder.() -> Unit = {}
     82 
     83         var parentRoute: Route? = null
     84             private set
     85 
     86         lateinit var context: RemoteSideContext
     87         lateinit var routeInfo: RouteInfo
     88         lateinit var routes: Routes
     89 
     90         val translation by lazy { context.translation.getCategory("manager.sections.${routeInfo.key.substringBefore("/")}")}
     91 
     92         private fun replaceArguments(id: String, args: Map<String, String>) = args.takeIf { it.isNotEmpty() }?.let {
     93             args.entries.fold(id) { acc, (key, value) ->
     94                 acc.replace("{$key}", value)
     95             }
     96         } ?: id
     97 
     98         fun navigate(args: MutableMap<String, String>.() -> Unit = {}) {
     99             routes.navController.navigate(replaceArguments(routeInfo.id, HashMap<String, String>().apply { args() }))
    100         }
    101 
    102         fun navigateReload() {
    103             routes.navController.navigate(routeInfo.id) {
    104                 popUpTo(routeInfo.id) { inclusive = true }
    105             }
    106         }
    107 
    108         fun navigateReset(args: MutableMap<String, String>.() -> Unit = {}) {
    109             routes.navController.navigate(replaceArguments(routeInfo.id, HashMap<String, String>().apply { args() })) {
    110                 popUpTo(routes.navController.graph.findStartDestination().id) {
    111                     saveState = true
    112                 }
    113                 launchSingleTop = true
    114                 restoreState = true
    115             }
    116         }
    117 
    118         fun parent(route: Route): Route {
    119             assert(route.routeInfo.primary) { "Parent route must be a primary route" }
    120             parentRoute = route
    121             return this
    122         }
    123     }
    124 
    125     val currentRoute: Route?
    126         get() = routes.firstOrNull { route ->
    127             navController.currentBackStackEntry?.destination?.hierarchy?.any { it.route == route.routeInfo.id } ?: false
    128         }
    129 
    130     val currentDestination: String?
    131         get() = navController.currentBackStackEntry?.destination?.route
    132 
    133     fun getCurrentRoute(navBackStackEntry: NavBackStackEntry?): Route? {
    134         if (navBackStackEntry == null) return null
    135 
    136         return navBackStackEntry.destination.hierarchy.firstNotNullOfOrNull { destination ->
    137             routes.firstOrNull { route ->
    138                 route.routeInfo.id == destination.route || route.routeInfo.childIds.contains(destination.route)
    139             }
    140         }
    141     }
    142 
    143     fun getRoutes(): List<Route> = routes
    144 
    145     private fun route(routeInfo: RouteInfo, route: Route): Route {
    146         route.apply {
    147             this.routeInfo = routeInfo
    148             routes = this@Routes
    149             context = this@Routes.context
    150             this.routeInfo.translatedKey = lazy { context.translation.getOrNull("manager.routes.${route.routeInfo.key.substringBefore("/")}") }
    151         }
    152         routes.add(route)
    153         return route
    154     }
    155 }