add navigator and use_navigate hook

This commit is contained in:
Adrian Wannenmacher committed 2022-12-13 00:09:32 +01:00
1 parent 85ac35c198
commit 0cc0cba482
6 files changed
+156 -3

No files matched your search

+3
View File
@@ -8,6 +8,9 @@ pub use name::*;
pub mod navigation;
mod navigator;
pub use navigator::*;
mod outlet;
pub use outlet::*;
+97
View File
@@ -0,0 +1,97 @@
use futures_channel::mpsc::UnboundedSender;
use crate::{navigation::NavigationTarget, RouterMessage};
/// A [`Navigator`] allowing for programmatic navigation.
///
/// The [`Navigator`] is not guaranteed to be able to trigger a navigation. When and if a navigation
/// is actually handled depends on the UI library.
pub struct Navigator<I> {
sender: UnboundedSender<RouterMessage<I>>,
}
impl<I> Navigator<I> {
/// Go back to the previous location.
///
/// Will fail silently if there is no previous location to go to.
pub fn go_back(&self) {
let _ = self.sender.unbounded_send(RouterMessage::GoBack);
}
/// Go back to the next location.
///
/// Will fail silently if there is no next location to go to.
pub fn go_forward(&self) {
let _ = self.sender.unbounded_send(RouterMessage::GoForward);
}
/// Push a new location.
///
/// The previous location will be available to go back to.
pub fn push(&self, target: impl Into<NavigationTarget>) {
let _ = self
.sender
.unbounded_send(RouterMessage::Push(target.into()));
}
/// Replace the current location.
///
/// The previous location will **not** be available to go back to.
pub fn replace(&self, target: impl Into<NavigationTarget>) {
let _ = self
.sender
.unbounded_send(RouterMessage::Replace(target.into()));
}
}
impl<I> From<UnboundedSender<RouterMessage<I>>> for Navigator<I> {
fn from(sender: UnboundedSender<RouterMessage<I>>) -> Self {
Self { sender }
}
}
#[cfg(test)]
mod tests {
use futures_channel::mpsc::{unbounded, UnboundedReceiver};
use super::*;
fn prepare() -> (Navigator<()>, UnboundedReceiver<RouterMessage<()>>) {
let (sender, receiver) = unbounded();
(Navigator::from(sender), receiver)
}
#[test]
fn go_back() {
let (n, mut s) = prepare();
n.go_back();
assert_eq!(s.try_next().unwrap(), Some(RouterMessage::GoBack));
}
#[test]
fn go_forward() {
let (n, mut s) = prepare();
n.go_forward();
assert_eq!(s.try_next().unwrap(), Some(RouterMessage::GoForward));
}
#[test]
fn push() {
let (n, mut s) = prepare();
let target = NavigationTarget::from("https://dioxuslabs.com/");
n.push(target.clone());
assert_eq!(s.try_next().unwrap(), Some(RouterMessage::Push(target)));
}
#[test]
fn replace() {
let (n, mut s) = prepare();
let target = NavigationTarget::from("https://dioxuslabs.com/");
n.replace(target.clone());
assert_eq!(s.try_next().unwrap(), Some(RouterMessage::Replace(target)));
}
}
+27
View File
@@ -1,5 +1,6 @@
use std::{
collections::{BTreeMap, HashMap, HashSet},
fmt::Debug,
sync::{Arc, Weak},
};
@@ -36,6 +37,32 @@ pub enum RouterMessage<I> {
GoForward,
}
impl<I: Debug> Debug for RouterMessage<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Subscribe(arg0) => f.debug_tuple("Subscribe").field(arg0).finish(),
Self::Push(arg0) => f.debug_tuple("Push").field(arg0).finish(),
Self::Replace(arg0) => f.debug_tuple("Replace").field(arg0).finish(),
Self::Update => write!(f, "Update"),
Self::GoBack => write!(f, "GoBack"),
Self::GoForward => write!(f, "GoForward"),
}
}
}
impl<I: PartialEq> PartialEq for RouterMessage<I> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Subscribe(l0), Self::Subscribe(r0)) => l0 == r0,
(Self::Push(l0), Self::Push(r0)) => l0 == r0,
(Self::Replace(l0), Self::Replace(r0)) => l0 == r0,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
impl<I: Eq> Eq for RouterMessage<I> {}
enum NavigationFailure {
External(String),
Named(Name),