Comments (6)
The
Voyager
integration module has no support to web history and the version injavascript
module is experimental. My knowledge in browser history is too limited. I made based on MDN documentation.About your sample code it is correct. We need do on each voyager navigation a browser history update.
To solve starting from a GET call, it is not too simple because you need to tell the Voyager about the path. Also check for history to avoid clean it. Something like
Maybe doing:
fun main() { val someLocker = ... val router = routing (...) { ... } VoyagerRouting( routing = router, content = { CurrentScreen() SideEffect { someLocker.unLock() } } ) // Is onpageshow called on browser or tab opened? I don't know. window.onpageshow = { someLocker.wait() val location = window.location // https://developer.mozilla.org/en-US/docs/Web/API/Location#examples val path = location.pathname + location.search + location.hash router.push|replace(path = path) } }
yep I actually updated the state manager for JS to match what the JS integration has more closely. I turned it into an expect/actual to make it work cross-platform.
internal expect object VoyagerRoutingStateManager {
fun init(routing: Routing, initialScreen: Screen)
suspend fun replaceAll(
call: ApplicationCall,
routing: Routing,
)
}
@Composable
public fun VoyagerRouting(
routing: Routing,
initialScreen: Screen,
disposeBehavior: NavigatorDisposeBehavior = NavigatorDisposeBehavior(),
onBackPressed: OnBackPressed = { true },
key: String = compositionUniqueId(),
content: NavigatorContent = { CurrentScreen() },
) {
CompositionLocalProvider(LocalVoyagerRouting provides routing) {
DisposableEffect(routing) {
VoyagerRoutingStateManager.init(routing, initialScreen)
onDispose {
routing.dispose()
}
}
Navigator(
screen = initialScreen,
disposeBehavior = disposeBehavior,
onBackPressed = onBackPressed,
key = key,
) { navigator ->
SideEffect {
routing.application.voyagerNavigator = navigator
}
content(navigator)
}
}
}
with JS being:
internal actual object VoyagerRoutingStateManager {
actual fun init(routing: Routing, initialScreen: Screen) {
// First time or page refresh we try continue from last state
val notified = routing.tryNotifyTheRoute(state = window.history.state)
resetOnPopStateEvent(routing)
if (!notified) {
val location = window.location
val path = location.pathname + location.search + location.hash
println(path)
routing.push(path = path)
}
}
actual suspend fun replaceAll(
call: ApplicationCall,
routing: Routing,
) {
while (true) {
window.history.replaceState(
title = "",
url = null,
data = null,
)
window.history.go(-1)
val forceBreak =
runCatching {
withTimeout(1_000) {
suspendCoroutine { continuation ->
window.onpopstate = { event ->
val state = event.state.deserialize()
continuation.resume(state == null)
}
}
}
}.getOrDefault(true)
if (forceBreak) {
break
}
}
window.history.replaceState(
title = "routing",
url = call.uri,
data = call.serialize(),
)
resetOnPopStateEvent(routing)
}
private fun resetOnPopStateEvent(routing: Routing) {
window.onpopstate = { event ->
routing.tryNotifyTheRoute(state = event.state)
}
}
private fun Routing.tryNotifyTheRoute(state: Any?): Boolean {
val javascriptState = state.deserialize() ?: return false
val call =
ApplicationCall(
application = application,
name = javascriptState.name,
uri = javascriptState.uri,
routeMethod = RouteMethod.parse(javascriptState.routeMethod),
parameters = parametersOf(javascriptState.parameters),
)
call.neglect = true
execute(call)
window.history.replaceState(
title = "routing",
url = call.uri,
data = call.serialize(),
)
push(javascriptState.uri)
return true
}
}
from kotlin-routing.
Was able to kang the browser history from js integration into voyagers and get it partially working.
However GET requests for a screen/path don't resolve yet (push's update the history).
in VoyagerRoutingBuilder.kt
:
@KtorDsl
public fun Route.screen(body: suspend PipelineContext<Unit, ApplicationCall>.() -> Screen) {
handle {
screen {
body(this)
}
+ call.handleScreenTransition()
}
}
+ expect suspend fun ApplicationCall.handleScreenTransition()
in my jsMain
actual suspend fun ApplicationCall.handleScreenTransition() {
when (routeMethod) {
RouteMethod.Push -> {
window.history.pushState(
title = "routing",
url = uri,
data = serialize()
)
}
RouteMethod.Replace -> {
window.history.replaceState(
title = "routing",
url = uri,
data = serialize(),
)
}
RouteMethod.ReplaceAll -> {
while (true) {
window.history.replaceState(
title = "",
url = null,
data = null,
)
window.history.go(-1)
val forceBreak =
runCatching {
withTimeout(1_000) {
suspendCoroutine { continuation ->
window.onpopstate = { event ->
val state = event.state.deserialize()
continuation.resume(state == null)
}
}
}
}.getOrDefault(true)
if (forceBreak) {
break
}
}
window.history.replaceState(
title = "routing",
url = uri,
data = serialize(),
)
}
}
}
@Serializable
internal data class JavascriptRoutingState(
val routeMethod: String,
val name: String,
val uri: String,
val parameters: Map<String, List<String>>,
)
internal fun ApplicationCall.serialize(): String {
val state =
JavascriptRoutingState(
routeMethod = routeMethod.value,
name = name,
uri = uri,
parameters = parameters.toMap(),
)
return Json.encodeToString(state)
}
internal fun Any?.deserialize(): JavascriptRoutingState? =
when (this) {
is String -> toState()
else -> null
}
private fun String.toState(): JavascriptRoutingState? =
runCatching {
Json.decodeFromString<JavascriptRoutingState>(this)
}.getOrNull()
and in my mobileMain (custom group for ios/android)
actual suspend fun ApplicationCall.handleScreenTransition() {}
from kotlin-routing.
The Voyager
integration module has no support to web history and the version in javascript
module is experimental.
My knowledge in browser history is too limited. I made based on MDN documentation.
About your sample code it is correct. We need do on each voyager navigation a browser history update.
To solve starting from a GET call, it is not too simple because you need to tell the Voyager about the path. Also check for history to avoid clean it. Something like
Maybe doing:
fun main() {
val someLocker = ...
val router = routing (...) { ... }
VoyagerRouting(
routing = router,
content = {
CurrentScreen()
SideEffect {
someLocker.unLock()
}
}
)
// Is onpageshow called on browser or tab opened? I don't know.
window.onpageshow = {
someLocker.wait()
val location = window.location
// https://developer.mozilla.org/en-US/docs/Web/API/Location#examples
val path = location.pathname + location.search + location.hash
router.push|replace(path = path)
}
}
from kotlin-routing.
Nice. I updated the javascript
integration to support history modes. Hash /#/
, Html5 History and Memory.
Most of these behaviors I will export to voyager
integration too.
from kotlin-routing.
Checkout release 0.0.15.
from kotlin-routing.
Latest releases starting from 0.0.17 should have support.
There is no support for WASM but it will be tracked in another issue.
from kotlin-routing.
Related Issues (4)
- Update to Voyager rc06 HOT 2
- Re-Add Voyager HOT 2
- WASM support
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from kotlin-routing.