use std::cell::{Cell, RefCell};
use day_reactive::Signal;
use day_spec::Edges;
use crate::tree::{has_tree, with_tree};
day_reactive::tls_slots! {
shield;
static DEFERRALS: RefCell<Vec<(u64, Edges)>> = const { RefCell::new(Vec::new()) };
static DISMISS_DISABLED: RefCell<Vec<u64>> = const { RefCell::new(Vec::new()) };
static STATUS_BAR: RefCell<Vec<(u64, bool)>> = const { RefCell::new(Vec::new()) };
static NEXT: Cell<u64> = const { Cell::new(1) };
static CHANGED: Cell<Option<Signal<u64>>> = const { Cell::new(None) };
}
fn changed_signal() -> Signal<u64> {
CHANGED.with(|c| match c.get() {
Some(s) => s,
None => {
let s = Signal::global(0);
c.set(Some(s));
s
}
})
}
fn next_token() -> u64 {
NEXT.with(|c| {
let t = c.get();
c.set(t + 1);
t
})
}
fn notify_changed() {
changed_signal().update(|v| *v = v.wrapping_add(1));
}
fn apply_deferral() {
let union = deferred_edges();
if has_tree() {
with_tree(|t| t.defer_system_gestures(union));
}
notify_changed();
}
pub fn push_gesture_deferral(edges: Edges) -> u64 {
let token = next_token();
DEFERRALS.with(|d| d.borrow_mut().push((token, edges)));
apply_deferral();
token
}
pub fn pop_gesture_deferral(token: u64) {
DEFERRALS.with(|d| d.borrow_mut().retain(|(t, _)| *t != token));
apply_deferral();
}
pub fn deferred_edges() -> Edges {
DEFERRALS.with(|d| {
d.borrow()
.iter()
.fold(Edges::NONE, |acc, (_, e)| acc.union(*e))
})
}
fn apply_status_bar() {
let hidden = status_bar_hidden();
if has_tree() {
with_tree(|t| t.set_status_bar_hidden(hidden));
}
}
pub fn push_status_bar_request(hidden: bool) -> u64 {
let token = next_token();
STATUS_BAR.with(|s| s.borrow_mut().push((token, hidden)));
apply_status_bar();
token
}
pub fn set_status_bar_request(token: u64, hidden: bool) {
let changed = STATUS_BAR.with(|s| {
let mut s = s.borrow_mut();
match s.iter_mut().find(|(t, _)| *t == token) {
Some((_, h)) if *h != hidden => {
*h = hidden;
true
}
_ => false,
}
});
if changed {
apply_status_bar();
}
}
pub fn pop_status_bar_request(token: u64) {
STATUS_BAR.with(|s| s.borrow_mut().retain(|(t, _)| *t != token));
apply_status_bar();
}
pub fn status_bar_hidden() -> bool {
STATUS_BAR.with(|s| s.borrow().iter().any(|(_, hidden)| *hidden))
}
pub fn push_dismiss_disabled() -> u64 {
let token = next_token();
DISMISS_DISABLED.with(|d| d.borrow_mut().push(token));
notify_changed();
token
}
pub fn pop_dismiss_disabled(token: u64) {
DISMISS_DISABLED.with(|d| d.borrow_mut().retain(|t| *t != token));
notify_changed();
}
pub fn dismiss_disabled() -> bool {
changed_signal().track();
DISMISS_DISABLED.with(|d| !d.borrow().is_empty())
}