use crate::*;
impl Console {
pub fn init() {
let signal: Signal<Vec<ConsoleEntry>> = Signal::create(Vec::new());
CONSOLE_LOG_SIGNAL.set(signal);
}
pub fn log<M>(message: M)
where
M: AsRef<str>,
{
let message_ref: &str = message.as_ref();
console::log_1(&message_ref.into());
Self::append_entry(ConsoleEntry::new(LogLevel::Log, message_ref.to_string()));
}
pub fn warn<M>(message: M)
where
M: AsRef<str>,
{
let message_ref: &str = message.as_ref();
console::warn_1(&message_ref.into());
Self::append_entry(ConsoleEntry::new(LogLevel::Warn, message_ref.to_string()));
}
pub fn error<M>(message: M)
where
M: AsRef<str>,
{
let message_ref: &str = message.as_ref();
console::error_1(&message_ref.into());
Self::append_entry(ConsoleEntry::new(LogLevel::Error, message_ref.to_string()));
}
pub fn clear() {
let log: Signal<Vec<ConsoleEntry>> = Self::get_signal();
log.set(Vec::new());
}
pub(crate) fn get_signal() -> Signal<Vec<ConsoleEntry>> {
CONSOLE_LOG_SIGNAL.get()
}
pub(crate) fn fab_on_click(panel_open: Signal<bool>) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |_: Event| {
let closer: Rc<dyn Fn()> = Rc::new(move || {
panel_open.set(false);
});
Router::overlay_stack_push(closer);
panel_open.set(true);
}))
}
pub(crate) fn filter_entries(
logs: Signal<Vec<ConsoleEntry>>,
filter: Signal<LogFilter>,
) -> Vec<(usize, ConsoleEntry)> {
let log_list: Vec<ConsoleEntry> = logs.get();
let filter_value: LogFilter = filter.get();
let mut result: Vec<(usize, ConsoleEntry)> = log_list
.iter()
.enumerate()
.filter(|(_, entry): &(usize, &ConsoleEntry)| match filter_value {
LogFilter::All => true,
LogFilter::Log => entry.get_level() == LogLevel::Log,
LogFilter::Warn => entry.get_level() == LogLevel::Warn,
LogFilter::Error => entry.get_level() == LogLevel::Error,
})
.map(|(index, entry): (usize, &ConsoleEntry)| (index, entry.clone()))
.collect();
result.reverse();
result
}
fn append_entry(entry: ConsoleEntry) {
let log: Signal<Vec<ConsoleEntry>> = Self::get_signal();
let mut current: Vec<ConsoleEntry> = log.get();
current.push(entry);
if current.len() > MAX_CONSOLE_LOG_ENTRIES {
let excess: usize = current.len() - MAX_CONSOLE_LOG_ENTRIES;
current.drain(0..excess);
}
log.set(current);
}
}
impl std::fmt::Display for LogFilter {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let label: &str = match self {
LogFilter::All => "All",
LogFilter::Log => "Log",
LogFilter::Warn => "Warn",
LogFilter::Error => "Error",
};
write!(formatter, "{}", label)
}
}
impl LogLevel {
pub(crate) fn badge(self) -> &'static str {
match self {
LogLevel::Log => "LOG",
LogLevel::Warn => "WRN",
LogLevel::Error => "ERR",
}
}
}
impl LogFilter {
pub(crate) fn on_filter_all(filter_signal: Signal<LogFilter>) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |_: Event| {
filter_signal.set(LogFilter::All);
}))
}
pub(crate) fn on_filter_log(filter_signal: Signal<LogFilter>) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |_: Event| {
filter_signal.set(LogFilter::Log);
}))
}
pub(crate) fn on_filter_warn(filter_signal: Signal<LogFilter>) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |_: Event| {
filter_signal.set(LogFilter::Warn);
}))
}
pub(crate) fn on_filter_error(filter_signal: Signal<LogFilter>) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |_: Event| {
filter_signal.set(LogFilter::Error);
}))
}
}