257 lines
6.7 KiB
Rust
257 lines
6.7 KiB
Rust
// path_from_the_root: src/orchestrator/router.rs
|
|
|
|
extern crate alloc;
|
|
|
|
use alloc::string::String;
|
|
use alloc::vec::Vec;
|
|
|
|
#[cfg(feature = "alloc")]
|
|
use hashbrown::HashMap;
|
|
|
|
use crate::component::Component;
|
|
use crate::focus::{FocusError, FocusManager};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum RouterEvent {
|
|
Navigated { from: Option<String>, to: String },
|
|
Back { to: String },
|
|
Forward { to: String },
|
|
}
|
|
|
|
pub struct Router<C: Component> {
|
|
#[cfg(feature = "alloc")]
|
|
pages: HashMap<String, C>,
|
|
#[cfg(not(feature = "alloc"))]
|
|
pages: Vec<(String, C)>,
|
|
current: Option<String>,
|
|
history: Vec<String>,
|
|
future: Vec<String>,
|
|
focus: FocusManager<C::Focus>,
|
|
}
|
|
|
|
impl<C: Component> Default for Router<C> {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl<C: Component> Router<C> {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
#[cfg(feature = "alloc")]
|
|
pages: HashMap::new(),
|
|
#[cfg(not(feature = "alloc"))]
|
|
pages: Vec::new(),
|
|
current: None,
|
|
history: Vec::new(),
|
|
future: Vec::new(),
|
|
focus: FocusManager::new(),
|
|
}
|
|
}
|
|
|
|
pub fn register(&mut self, id: String, mut page: C) {
|
|
#[cfg(feature = "alloc")]
|
|
{
|
|
if self.current.as_ref() == Some(&id) {
|
|
let _ = page.on_enter();
|
|
let targets = page.targets();
|
|
self.focus.set_targets(targets.to_vec());
|
|
}
|
|
self.pages.insert(id, page);
|
|
}
|
|
|
|
#[cfg(not(feature = "alloc"))]
|
|
{
|
|
if self.current.as_ref() == Some(&id) {
|
|
let _ = page.on_enter();
|
|
let targets = page.targets();
|
|
self.focus.set_targets(targets.to_vec());
|
|
}
|
|
self.pages.push((id, page));
|
|
}
|
|
}
|
|
|
|
fn get_page_mut(&mut self, id: &str) -> Option<&mut C> {
|
|
#[cfg(feature = "alloc")]
|
|
{
|
|
self.pages.get_mut(id)
|
|
}
|
|
|
|
#[cfg(not(feature = "alloc"))]
|
|
{
|
|
self.pages
|
|
.iter_mut()
|
|
.find(|(page_id, _)| page_id == id)
|
|
.map(|(_, page)| page)
|
|
}
|
|
}
|
|
|
|
fn get_page(&self, id: &str) -> Option<&C> {
|
|
#[cfg(feature = "alloc")]
|
|
{
|
|
self.pages.get(id)
|
|
}
|
|
|
|
#[cfg(not(feature = "alloc"))]
|
|
{
|
|
self.pages
|
|
.iter()
|
|
.find(|(page_id, _)| page_id == id)
|
|
.map(|(_, page)| page)
|
|
}
|
|
}
|
|
|
|
pub fn navigate(&mut self, id: String) -> Result<Option<RouterEvent>, FocusError> {
|
|
let result = if let Some(current_id) = self.current.take() {
|
|
if let Some(current_page) = self.get_page_mut(¤t_id) {
|
|
let _ = current_page.on_exit();
|
|
}
|
|
self.history.push(current_id.clone());
|
|
self.future.clear();
|
|
Some(RouterEvent::Navigated {
|
|
from: Some(current_id),
|
|
to: id.clone(),
|
|
})
|
|
} else {
|
|
Some(RouterEvent::Navigated {
|
|
from: None,
|
|
to: id.clone(),
|
|
})
|
|
};
|
|
|
|
let targets = if let Some(page) = self.get_page_mut(&id) {
|
|
let _ = page.on_enter();
|
|
Some(page.targets().to_vec())
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if let Some(targets) = targets {
|
|
self.focus.set_targets(targets);
|
|
}
|
|
|
|
self.current = Some(id);
|
|
Ok(result)
|
|
}
|
|
|
|
pub fn back(&mut self) -> Result<Option<RouterEvent>, FocusError> {
|
|
if let Some(current) = self.current.take() {
|
|
if let Some(from) = self.history.pop() {
|
|
self.future.push(current.clone());
|
|
let to = from.clone();
|
|
|
|
if let Some(current_page) = self.get_page_mut(¤t) {
|
|
let _ = current_page.on_exit();
|
|
}
|
|
|
|
self.current = Some(to.clone());
|
|
|
|
let targets = if let Some(page) = self.get_page_mut(&to) {
|
|
let _ = page.on_enter();
|
|
Some(page.targets().to_vec())
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if let Some(targets) = targets {
|
|
self.focus.set_targets(targets);
|
|
}
|
|
|
|
Ok(Some(RouterEvent::Back { to }))
|
|
} else {
|
|
self.current = Some(current);
|
|
Ok(None)
|
|
}
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
|
|
pub fn forward(&mut self) -> Result<Option<RouterEvent>, FocusError> {
|
|
if let Some(current) = self.current.take() {
|
|
if let Some(from) = self.future.pop() {
|
|
self.history.push(current.clone());
|
|
let to = from.clone();
|
|
|
|
if let Some(current_page) = self.get_page_mut(¤t) {
|
|
let _ = current_page.on_exit();
|
|
}
|
|
|
|
self.current = Some(to.clone());
|
|
|
|
let targets = if let Some(page) = self.get_page_mut(&to) {
|
|
let _ = page.on_enter();
|
|
Some(page.targets().to_vec())
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if let Some(targets) = targets {
|
|
self.focus.set_targets(targets);
|
|
}
|
|
|
|
Ok(Some(RouterEvent::Forward { to }))
|
|
} else {
|
|
self.current = Some(current);
|
|
Ok(None)
|
|
}
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
|
|
pub fn current(&self) -> Option<&C> {
|
|
self.current.as_ref().and_then(|id| self.get_page(id))
|
|
}
|
|
|
|
pub fn current_mut(&mut self) -> Option<&mut C> {
|
|
if let Some(id) = self.current.clone() {
|
|
self.get_page_mut(&id)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn current_id(&self) -> Option<&String> {
|
|
self.current.as_ref()
|
|
}
|
|
|
|
pub fn focus_manager(&self) -> &FocusManager<C::Focus> {
|
|
&self.focus
|
|
}
|
|
|
|
pub fn focus_manager_mut(&mut self) -> &mut FocusManager<C::Focus> {
|
|
&mut self.focus
|
|
}
|
|
|
|
pub fn history(&self) -> &[String] {
|
|
&self.history
|
|
}
|
|
|
|
pub fn future(&self) -> &[String] {
|
|
&self.future
|
|
}
|
|
|
|
pub fn page_count(&self) -> usize {
|
|
#[cfg(feature = "alloc")]
|
|
{
|
|
self.pages.len()
|
|
}
|
|
#[cfg(not(feature = "alloc"))]
|
|
{
|
|
self.pages.len()
|
|
}
|
|
}
|
|
|
|
pub fn has_page(&self, id: &str) -> bool {
|
|
#[cfg(feature = "alloc")]
|
|
{
|
|
self.pages.contains_key(id)
|
|
}
|
|
#[cfg(not(feature = "alloc"))]
|
|
{
|
|
self.pages.iter().any(|(page_id, _)| page_id == id)
|
|
}
|
|
}
|
|
}
|