it almost lives?
This commit is contained in:
1 parent
d637ef187c
commit
5f0dd3af3e
43 files changed
+506
-244
No files matched your search
@@ -1,10 +1,10 @@
|
||||
use crate::prelude::{ExternalNavigationFailure, GenericRouterContext, NavigationTarget, Routable};
|
||||
use crate::prelude::{ExternalNavigationFailure, NavigationTarget, Routable, RouterContext};
|
||||
|
||||
/// A view into the navigation state of a router.
|
||||
#[derive(Clone)]
|
||||
pub struct GenericNavigator<R: Routable>(pub(crate) GenericRouterContext<R>);
|
||||
pub struct GenericNavigator(pub(crate) RouterContext);
|
||||
|
||||
impl<R: Routable> GenericNavigator<R> {
|
||||
impl GenericNavigator {
|
||||
/// Check whether there is a previous page to navigate back to.
|
||||
#[must_use]
|
||||
pub fn can_go_back(&self) -> bool {
|
||||
@@ -34,7 +34,7 @@ impl<R: Routable> GenericNavigator<R> {
|
||||
/// Push a new location.
|
||||
///
|
||||
/// The previous location will be available to go back to.
|
||||
pub fn push(
|
||||
pub fn push<R: Routable>(
|
||||
&self,
|
||||
target: impl Into<NavigationTarget<R>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
@@ -44,7 +44,7 @@ impl<R: Routable> GenericNavigator<R> {
|
||||
/// Replace the current location.
|
||||
///
|
||||
/// The previous location will **not** be available to go back to.
|
||||
pub fn replace(
|
||||
pub fn replace<R: Routable>(
|
||||
&self,
|
||||
target: impl Into<NavigationTarget<R>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
|
||||
@@ -31,7 +31,7 @@ impl<R> OutletContext<R> {
|
||||
where
|
||||
R: Routable + Clone,
|
||||
{
|
||||
let router = use_router_internal::<R>(cx)
|
||||
let router = use_router_internal(cx)
|
||||
.as_ref()
|
||||
.expect("Outlet must be inside of a router");
|
||||
let outlet: &OutletContext<R> = use_outlet_context(cx);
|
||||
@@ -51,6 +51,6 @@ impl<R> OutletContext<R> {
|
||||
}
|
||||
}
|
||||
|
||||
router.current().render(cx, current_level)
|
||||
router.current::<R>().render(cx, current_level)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::{
|
||||
any::Any,
|
||||
collections::HashSet,
|
||||
sync::{Arc, RwLock, RwLockWriteGuard},
|
||||
};
|
||||
@@ -6,7 +7,7 @@ use std::{
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::{
|
||||
history::HistoryProvider, navigation::NavigationTarget, routable::Routable,
|
||||
navigation::NavigationTarget, prelude::AnyHistoryProvider, routable::Routable,
|
||||
router_cfg::RouterConfig,
|
||||
};
|
||||
|
||||
@@ -15,52 +16,31 @@ use crate::{
|
||||
pub struct ExternalNavigationFailure(String);
|
||||
|
||||
/// A function the router will call after every routing update.
|
||||
pub(crate) type RoutingCallback<R> =
|
||||
Arc<dyn Fn(GenericRouterContext<R>) -> Option<NavigationTarget<R>>>;
|
||||
pub(crate) type RoutingCallback<R> = Arc<dyn Fn(LinkContext<R>) -> Option<NavigationTarget<R>>>;
|
||||
|
||||
struct MutableRouterState<R>
|
||||
where
|
||||
R: Routable,
|
||||
{
|
||||
struct MutableRouterState {
|
||||
/// The current prefix.
|
||||
prefix: Option<String>,
|
||||
|
||||
history: Box<dyn HistoryProvider<R>>,
|
||||
history: Box<dyn AnyHistoryProvider>,
|
||||
|
||||
unresolved_error: Option<ExternalNavigationFailure>,
|
||||
}
|
||||
|
||||
/// A collection of router data that manages all routing functionality.
|
||||
pub struct GenericRouterContext<R>
|
||||
where
|
||||
R: Routable,
|
||||
{
|
||||
state: Arc<RwLock<MutableRouterState<R>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct RouterContext {
|
||||
state: Arc<RwLock<MutableRouterState>>,
|
||||
|
||||
subscribers: Arc<RwLock<HashSet<ScopeId>>>,
|
||||
subscriber_update: Arc<dyn Fn(ScopeId)>,
|
||||
routing_callback: Option<RoutingCallback<R>>,
|
||||
routing_callback: Option<Arc<dyn Fn(RouterContext) -> Option<NavigationTarget<Box<dyn Any>>>>>,
|
||||
|
||||
failure_external_navigation: fn(Scope) -> Element,
|
||||
}
|
||||
|
||||
impl<R: Routable> Clone for GenericRouterContext<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
state: self.state.clone(),
|
||||
subscribers: self.subscribers.clone(),
|
||||
subscriber_update: self.subscriber_update.clone(),
|
||||
routing_callback: self.routing_callback.clone(),
|
||||
failure_external_navigation: self.failure_external_navigation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> GenericRouterContext<R>
|
||||
where
|
||||
R: Routable,
|
||||
{
|
||||
pub(crate) fn new(
|
||||
impl RouterContext {
|
||||
pub(crate) fn new<R: Routable + 'static>(
|
||||
mut cfg: RouterConfig<R>,
|
||||
mark_dirty: Arc<dyn Fn(ScopeId) + Sync + Send>,
|
||||
) -> Self
|
||||
@@ -82,7 +62,21 @@ where
|
||||
subscribers: subscribers.clone(),
|
||||
subscriber_update,
|
||||
|
||||
routing_callback: cfg.on_update,
|
||||
routing_callback: cfg.on_update.map(|update| {
|
||||
Arc::new(move |ctx| {
|
||||
let ctx = LinkContext {
|
||||
inner: ctx,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
update(ctx).map(|t| match t {
|
||||
NavigationTarget::Internal(r) => {
|
||||
NavigationTarget::Internal(Box::new(r) as Box<dyn Any>)
|
||||
}
|
||||
NavigationTarget::External(s) => NavigationTarget::External(s),
|
||||
})
|
||||
})
|
||||
as Arc<dyn Fn(RouterContext) -> Option<NavigationTarget<Box<dyn Any>>>>
|
||||
}),
|
||||
|
||||
failure_external_navigation: cfg.failure_external_navigation,
|
||||
};
|
||||
@@ -100,6 +94,11 @@ where
|
||||
myself
|
||||
}
|
||||
|
||||
pub(crate) fn route_from_str(&self, route: &str) -> Result<Box<dyn Any>, String> {
|
||||
let state = self.state.read().unwrap();
|
||||
state.history.parse_route(route)
|
||||
}
|
||||
|
||||
/// Check whether there is a previous page to navigate back to.
|
||||
#[must_use]
|
||||
pub fn can_go_back(&self) -> bool {
|
||||
@@ -134,14 +133,10 @@ where
|
||||
self.change_route();
|
||||
}
|
||||
|
||||
/// Push a new location.
|
||||
///
|
||||
/// The previous location will be available to go back to.
|
||||
pub fn push(
|
||||
pub(crate) fn push_any(
|
||||
&self,
|
||||
target: impl Into<NavigationTarget<R>>,
|
||||
target: NavigationTarget<Box<dyn Any>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
let target = target.into();
|
||||
match target {
|
||||
NavigationTarget::Internal(p) => {
|
||||
let mut state = self.state_mut();
|
||||
@@ -153,10 +148,29 @@ where
|
||||
self.change_route()
|
||||
}
|
||||
|
||||
/// Push a new location.
|
||||
///
|
||||
/// The previous location will be available to go back to.
|
||||
pub fn push<R: Routable>(
|
||||
&self,
|
||||
target: impl Into<NavigationTarget<R>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
let target = target.into();
|
||||
match target {
|
||||
NavigationTarget::Internal(p) => {
|
||||
let mut state = self.state_mut();
|
||||
state.history.push(Box::new(p))
|
||||
}
|
||||
NavigationTarget::External(e) => return self.external(e),
|
||||
}
|
||||
|
||||
self.change_route()
|
||||
}
|
||||
|
||||
/// Replace the current location.
|
||||
///
|
||||
/// The previous location will **not** be available to go back to.
|
||||
pub fn replace(
|
||||
pub fn replace<R: Routable>(
|
||||
&self,
|
||||
target: impl Into<NavigationTarget<R>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
@@ -165,7 +179,7 @@ where
|
||||
{
|
||||
let mut state = self.state_mut();
|
||||
match target {
|
||||
NavigationTarget::Internal(p) => state.history.replace(p),
|
||||
NavigationTarget::Internal(p) => state.history.replace(Box::new(p)),
|
||||
NavigationTarget::External(e) => return self.external(e),
|
||||
}
|
||||
}
|
||||
@@ -174,11 +188,24 @@ where
|
||||
}
|
||||
|
||||
/// The route that is currently active.
|
||||
pub fn current(&self) -> R
|
||||
where
|
||||
R: Clone,
|
||||
{
|
||||
self.state.read().unwrap().history.current_route()
|
||||
pub fn current<R: Routable>(&self) -> R {
|
||||
self.state
|
||||
.read()
|
||||
.unwrap()
|
||||
.history
|
||||
.current_route()
|
||||
.downcast::<R>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// The route that is currently active.
|
||||
pub fn current_route_string(&self) -> String {
|
||||
self.state
|
||||
.read()
|
||||
.unwrap()
|
||||
.history
|
||||
.current_route()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// The prefix that is currently active.
|
||||
@@ -201,7 +228,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn state_mut(&self) -> RwLockWriteGuard<MutableRouterState<R>> {
|
||||
fn state_mut(&self) -> RwLockWriteGuard<MutableRouterState> {
|
||||
self.state.write().unwrap()
|
||||
}
|
||||
|
||||
@@ -254,3 +281,87 @@ where
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LinkContext<R> {
|
||||
inner: RouterContext,
|
||||
_marker: std::marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<R> LinkContext<R>
|
||||
where
|
||||
R: Routable,
|
||||
{
|
||||
/// Check whether there is a previous page to navigate back to.
|
||||
#[must_use]
|
||||
pub fn can_go_back(&self) -> bool {
|
||||
self.inner.can_go_back()
|
||||
}
|
||||
|
||||
/// Check whether there is a future page to navigate forward to.
|
||||
#[must_use]
|
||||
pub fn can_go_forward(&self) -> bool {
|
||||
self.inner.can_go_forward()
|
||||
}
|
||||
|
||||
/// Go back to the previous location.
|
||||
///
|
||||
/// Will fail silently if there is no previous location to go to.
|
||||
pub fn go_back(&self) {
|
||||
self.inner.go_back();
|
||||
}
|
||||
|
||||
/// Go back to the next location.
|
||||
///
|
||||
/// Will fail silently if there is no next location to go to.
|
||||
pub fn go_forward(&self) {
|
||||
self.inner.go_forward();
|
||||
}
|
||||
|
||||
/// Push a new location.
|
||||
///
|
||||
/// The previous location will be available to go back to.
|
||||
pub fn push(
|
||||
&self,
|
||||
target: impl Into<NavigationTarget<R>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
self.inner.push(target)
|
||||
}
|
||||
|
||||
/// Replace the current location.
|
||||
///
|
||||
/// The previous location will **not** be available to go back to.
|
||||
pub fn replace(
|
||||
&self,
|
||||
target: impl Into<NavigationTarget<R>>,
|
||||
) -> Option<ExternalNavigationFailure> {
|
||||
self.inner.replace(target)
|
||||
}
|
||||
|
||||
/// The route that is currently active.
|
||||
pub fn current(&self) -> R
|
||||
where
|
||||
R: Clone,
|
||||
{
|
||||
self.inner.current()
|
||||
}
|
||||
|
||||
/// The prefix that is currently active.
|
||||
pub fn prefix(&self) -> Option<String> {
|
||||
self.inner.prefix()
|
||||
}
|
||||
|
||||
/// Manually subscribe to the current route
|
||||
pub fn subscribe(&self, id: ScopeId) {
|
||||
self.inner.subscribe(id)
|
||||
}
|
||||
|
||||
/// Manually unsubscribe from the current route
|
||||
pub fn unsubscribe(&self, id: ScopeId) {
|
||||
self.inner.unsubscribe(id)
|
||||
}
|
||||
|
||||
/// Clear any unresolved errors
|
||||
pub fn clear_error(&self) {
|
||||
self.inner.clear_error()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user