1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! The status bar's notice, and the messages list of every one shown.
use std::collections::VecDeque;
use crate::ui::bars::Notice;
use crate::state::{Cmd, Timer};
/// How many notices the messages list keeps.
const KEPT: usize = 50;
/// What the status bar says. Saying is the only way to show a notice, and
/// each saying is numbered, so it gets a timer and a messages entry of its
/// own and only its own timer clears it.
#[derive(Default)]
pub struct Notices {
/// The notice showing, and its number.
shown: Option<(u64, Notice)>,
/// The last number given, and the last given a timer.
said: u64,
timed: u64,
/// Notices shown this session, newest first, with when (Unix seconds).
log: VecDeque<(u64, Notice)>,
}
impl Notices {
/// Says `text` for a few seconds.
pub fn info(&mut self, text: impl Into<String>) {
self.say(Notice::Info(text.into()));
}
/// Says what went wrong, for longer.
pub fn error(&mut self, text: impl Into<String>) {
self.say(Notice::Error(text.into()));
}
/// Shows `notice`, under a new number.
pub fn say(&mut self, notice: Notice) {
self.said += 1;
self.shown = Some((self.said, notice));
}
/// Clears the notice showing, and gives it back.
pub fn dismiss(&mut self) -> Option<Notice> {
self.shown.take().map(|(_, notice)| notice)
}
/// Notice number `id`'s time is up: cleared, if it's still showing.
pub fn expire(&mut self, id: u64) {
self.shown = self.shown.take().filter(|(shown, _)| *shown != id);
}
pub fn shown(&self) -> Option<&Notice> {
self.shown.as_ref().map(|(_, notice)| notice)
}
pub fn log(&self) -> &VecDeque<(u64, Notice)> {
&self.log
}
/// The timer for a notice said since the last call (errors stay
/// longer), which is logged as shown at `clock`'s now.
pub fn timer(&mut self, clock: fn() -> u64) -> Option<Cmd> {
let (id, notice) = self.shown.as_ref().filter(|(id, _)| *id != self.timed)?;
self.timed = *id;
self.log.push_front((clock(), notice.clone()));
self.log.truncate(KEPT);
let ms = match notice {
Notice::Info(_) => 4_000,
Notice::Error(_) => 10_000,
};
Some(Cmd::Timer(Timer::ExpireNotice(*id), ms))
}
}