Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename Route -> RouteDecisionHandler #46

Merged
merged 1 commit into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions core/src/main/kotlin/dev/hotwire/core/config/Hotwire.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import dev.hotwire.core.bridge.BridgeComponent
import dev.hotwire.core.bridge.BridgeComponentFactory
import dev.hotwire.core.navigation.fragments.HotwireWebBottomSheetFragment
import dev.hotwire.core.navigation.fragments.HotwireWebFragment
import dev.hotwire.core.navigation.routing.AppNavigationRoute
import dev.hotwire.core.navigation.routing.BrowserRoute
import dev.hotwire.core.navigation.routing.AppNavigationRouteDecisionHandler
import dev.hotwire.core.navigation.routing.BrowserRouteDecisionHandler
import dev.hotwire.core.navigation.routing.Router
import dev.hotwire.core.turbo.config.PathConfiguration
import kotlin.reflect.KClass
Expand All @@ -25,8 +25,8 @@ object Hotwire {
private set

internal var router = Router(listOf(
AppNavigationRoute(),
BrowserRoute()
AppNavigationRouteDecisionHandler(),
BrowserRouteDecisionHandler()
))

val config: HotwireConfig = HotwireConfig()
Expand All @@ -45,11 +45,11 @@ object Hotwire {
}

/**
* Registers the [Router.Route] instances that determine whether to route location
* Registers the [Router.RouteDecisionHandler] instances that determine whether to route location
* urls within in-app navigation or with alternative custom behaviors.
*/
fun registerRoutes(routes: List<Router.Route>) {
router = Router(routes)
fun registerRouteDecisionHandlers(decisionHandlers: List<Router.RouteDecisionHandler>) {
router = Router(decisionHandlers)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class Navigator(
extras: FragmentNavigator.Extras? = null
) {

if (getRouteResult(location) == Router.RouteResult.STOP) {
if (getRouteDecision(location) == Router.Decision.CANCEL) {
return
}

Expand Down Expand Up @@ -350,15 +350,15 @@ class Navigator(
return currentDestination.navigatorForNavigation(location).navController
}

private fun getRouteResult(location: String): Router.RouteResult {
val result = currentDestination.route(location)
private fun getRouteDecision(location: String): Router.Decision {
val decision = currentDestination.decideRoute(location)

logEvent(
"routeResult",
"routeDecision",
"location" to location,
"result" to result
"decision" to decision
)
return result
return decision
}

private fun navOptions(location: String, action: VisitAction): NavOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import androidx.core.net.toUri
import dev.hotwire.core.navigation.activities.HotwireActivity
import dev.hotwire.core.navigation.navigator.NavigatorConfiguration

class AppNavigationRoute : Router.Route {
class AppNavigationRouteDecisionHandler : Router.RouteDecisionHandler {
override val name = "app-navigation"

override val result = Router.RouteResult.NAVIGATE
override val decision = Router.Decision.NAVIGATE

override fun matches(
location: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import dev.hotwire.core.lib.logging.logError
import dev.hotwire.core.navigation.activities.HotwireActivity
import dev.hotwire.core.navigation.navigator.NavigatorConfiguration

class BrowserRoute : Router.Route {
class BrowserRouteDecisionHandler : Router.RouteDecisionHandler {
override val name = "browser"

override val result = Router.RouteResult.STOP
override val decision = Router.Decision.CANCEL

override fun matches(
location: String,
Expand All @@ -29,7 +29,7 @@ class BrowserRoute : Router.Route {
try {
activity.startActivity(intent)
} catch (e: ActivityNotFoundException) {
logError("BrowserRoute", e)
logError("BrowserRouteDecisionHandler", e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import dev.hotwire.core.navigation.activities.HotwireActivity
import dev.hotwire.core.navigation.navigator.NavigatorConfiguration
import dev.hotwire.core.turbo.util.colorFromThemeAttr

class BrowserTabRoute : Router.Route {
class BrowserTabRouteDecisionHandler : Router.RouteDecisionHandler {
override val name = "browser-tab"

override val result = Router.RouteResult.STOP
override val decision = Router.Decision.CANCEL

override fun matches(
location: String,
Expand Down
51 changes: 26 additions & 25 deletions core/src/main/kotlin/dev/hotwire/core/navigation/routing/Router.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,35 @@ package dev.hotwire.core.navigation.routing
import dev.hotwire.core.lib.logging.logEvent
import dev.hotwire.core.navigation.activities.HotwireActivity
import dev.hotwire.core.navigation.navigator.NavigatorConfiguration
import dev.hotwire.core.navigation.routing.Router.Route
import dev.hotwire.core.navigation.routing.Router.RouteDecisionHandler

/**
* Routes location urls within in-app navigation or with custom behaviors
* provided in [Route] instances.
* provided in [RouteDecisionHandler] instances.
*/
class Router(private val routes: List<Route>) {
class Router(private val decisionHandlers: List<RouteDecisionHandler>) {

/**
* An interface to implement to provide custom route behaviors in your app.
* An interface to implement to provide custom route decision handling
* behaviors in your app.
*/
interface Route {
interface RouteDecisionHandler {
/**
* The route name used in debug logging.
* The decision handler name used in debug logging.
*/
val name: String

/**
* To permit in-app navigation when the location matches this route,
* return [RouteResult.NAVIGATE]. To prevent in-app navigation return
* [RouteResult.STOP].
* To permit in-app navigation when the location matches this decision
* handler, return [Decision.NAVIGATE]. To prevent in-app navigation
* return [Decision.CANCEL].
*/
val result: RouteResult
val decision: Decision

/**
* Determines whether the location matches this route. Use your own custom
* rules based on the location's domain, protocol, path, or any other
* factors.
* Determines whether the location matches this decision handler. Use
* your own custom rules based on the location's domain, protocol,
* path, or any other factors.
*/
fun matches(
location: String,
Expand All @@ -48,7 +49,7 @@ class Router(private val routes: List<Route>) {
)
}

enum class RouteResult {
enum class Decision {
/**
* Permit in-app navigation with your app's domain urls.
*/
Expand All @@ -57,27 +58,27 @@ class Router(private val routes: List<Route>) {
/**
* Prevent in-app navigation. Always use this for external domain urls.
*/
STOP
CANCEL
}

internal fun route(
internal fun decideRoute(
location: String,
configuration: NavigatorConfiguration,
activity: HotwireActivity
): RouteResult {
routes.forEach { route ->
if (route.matches(location, configuration)) {
logEvent("routeMatch", listOf(
"route" to route.name,
): Decision {
decisionHandlers.forEach { handler ->
if (handler.matches(location, configuration)) {
logEvent("handlerMatch", listOf(
"handler" to handler.name,
"location" to location
))

route.handle(location, configuration, activity)
return route.result
handler.handle(location, configuration, activity)
return handler.decision
}
}

logEvent("noRouteForLocation", location)
return RouteResult.STOP
logEvent("noHandlerForLocation", location)
return Decision.CANCEL
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ interface HotwireNavDestination {

/**
* Determines whether the new location should be routed within in-app navigation from the
* current destination. By default, the registered [Router.Route] instances are used to
* current destination. By default, the registered [Router.RouteDecisionHandler] instances are used to
* determine routing logic. You can override the global behavior for a specific destination,
* but it's recommend to use dedicated [Router.Route] instances for routing logic.
* but it's recommend to use dedicated [Router.RouteDecisionHandler] instances for routing logic.
*/
fun route(newLocation: String): Router.RouteResult {
return Hotwire.router.route(
fun decideRoute(newLocation: String): Router.Decision {
return Hotwire.router.decideRoute(
location = newLocation,
configuration = navigator.configuration,
activity = fragment.requireActivity() as HotwireActivity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class AppNavigationRouteTest {
private val route = AppNavigationRoute()
class AppNavigationRouteDecisionHandlerTest {
private val route = AppNavigationRouteDecisionHandler()
private val config = NavigatorConfiguration(
name = "test",
startLocation = "https://my.app.com",
Expand All @@ -17,7 +17,7 @@ class AppNavigationRouteTest {

@Test
fun `matching result navigates`() {
assertEquals(Router.RouteResult.NAVIGATE, route.result)
assertEquals(Router.Decision.NAVIGATE, route.decision)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class BrowserTabRouteTest {
private val route = BrowserTabRoute()
class BrowserRouteDecisionHandlerTest {
private val route = BrowserRouteDecisionHandler()
private val config = NavigatorConfiguration(
name = "test",
startLocation = "https://my.app.com",
Expand All @@ -17,7 +17,7 @@ class BrowserTabRouteTest {

@Test
fun `matching result stops navigation`() {
assertEquals(Router.RouteResult.STOP, route.result)
assertEquals(Router.Decision.CANCEL, route.decision)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class BrowserRouteTest {
private val route = BrowserRoute()
class BrowserTabRouteDecisionHandlerTest {
private val route = BrowserTabRouteDecisionHandler()
private val config = NavigatorConfiguration(
name = "test",
startLocation = "https://my.app.com",
Expand All @@ -17,7 +17,7 @@ class BrowserRouteTest {

@Test
fun `matching result stops navigation`() {
assertEquals(Router.RouteResult.STOP, route.result)
assertEquals(Router.Decision.CANCEL, route.decision)
}

@Test
Expand Down
12 changes: 6 additions & 6 deletions demo/src/main/kotlin/dev/hotwire/demo/DemoApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import dev.hotwire.core.BuildConfig
import dev.hotwire.core.bridge.BridgeComponentFactory
import dev.hotwire.core.bridge.KotlinXJsonConverter
import dev.hotwire.core.config.Hotwire
import dev.hotwire.core.navigation.routing.AppNavigationRoute
import dev.hotwire.core.navigation.routing.BrowserTabRoute
import dev.hotwire.core.navigation.routing.AppNavigationRouteDecisionHandler
import dev.hotwire.core.navigation.routing.BrowserTabRouteDecisionHandler
import dev.hotwire.core.turbo.config.PathConfiguration
import dev.hotwire.demo.bridge.FormComponent
import dev.hotwire.demo.bridge.MenuComponent
Expand Down Expand Up @@ -59,10 +59,10 @@ class DemoApplication : Application() {
BridgeComponentFactory("overflow-menu", ::OverflowMenuComponent)
))

// Register routes
Hotwire.registerRoutes(listOf(
AppNavigationRoute(),
BrowserTabRoute()
// Register route decision handlers
Hotwire.registerRouteDecisionHandlers(listOf(
AppNavigationRouteDecisionHandler(),
BrowserTabRouteDecisionHandler()
))

// Set configuration options
Expand Down
Loading