use crate::reply::queue::QueueRow;
use crate::ui::{Channel, Model, theme};
pub const WORD: &str = "attention";
pub const HEADING: &str = "waiting on you";
pub const NOT_ANSWERED: &str = "waiting to hear what is asking for you";
pub const NOTHING: &str = "nothing is waiting on you — a conversation that asks will appear here";
pub const SEEN: &str = "seen";
pub const GO: &str = "go to it";
pub const WIDER: &str = "…and every call like it:";
pub fn wider(verdict: &str, scope: &str) -> String {
format!("{verdict} for this {scope}")
}
pub fn render(ui: &mut egui::Ui, model: &mut Model) -> bool {
if !model.showing(crate::ui::Listing::Queue) {
return false;
}
crate::ui::overlay::name(ui, HEADING);
ui.add_space(theme::space::S);
if model.waiting.is_empty() {
theme::paint::empty(ui, NOT_ANSWERED);
return true;
}
let sections = model.sections();
if sections.iter().all(|section| section.rows.is_empty()) {
theme::paint::empty(ui, NOTHING);
return true;
}
egui::ScrollArea::vertical()
.id_salt(HEADING)
.auto_shrink(false)
.show(ui, |ui| {
for section in §ions {
if section.rows.is_empty() {
continue;
}
ui.add_space(theme::space::S);
ui.colored_label(theme::INK_WEAK, section.header.clone());
for (channel, row) in §ion.rows {
waiting_row(ui, model, channel, row);
}
}
});
true
}
fn waiting_row(ui: &mut egui::Ui, model: &mut Model, channel: &Channel, row: &QueueRow) {
let (mark, ink) = mark(row);
theme::paint::marked(
ui,
(&mark, ink),
&headline(row),
theme::INK,
Some(theme::accent(theme::State::Attention)),
false,
0.0,
);
if let Some(said) = flagged(row) {
ui.colored_label(theme::accent(theme::State::Annotation), said);
}
if let Some(said) = row.failure.clone() {
ui.colored_label(theme::accent(theme::State::Error), said);
}
if let Some(said) = parked(row) {
ui.colored_label(theme::accent(theme::State::Annotation), said);
}
if let Some(said) = signalled(row) {
ui.colored_label(theme::INK_WEAK, said);
}
if !row.preview.is_empty() {
ui.colored_label(theme::INK_WEAK, row.preview.clone());
}
acts(ui, model, channel, row);
}
fn acts(ui: &mut egui::Ui, model: &mut Model, channel: &Channel, row: &QueueRow) {
if model.wall(channel, &row.workspace).is_none() {
ui.colored_label(
theme::accent(theme::State::Annotation),
crate::ui::roster::NO_NAME_HERE,
);
return;
}
let offered = crate::ui::ask::choices(row);
let mut taken = None;
let mut seat = |ui: &mut egui::Ui, choice: &crate::ui::ask::Choice| {
let seat = ui.button(choice.word());
crate::ui::act::tag(&seat, &[choice.op()]);
if seat.clicked() {
taken = Some(*choice);
}
};
ui.horizontal_wrapped(|ui| {
ui.add_space(theme::space::L);
for choice in offered.iter().filter(|choice| !choice.wider()) {
seat(ui, choice);
}
if ui.button(GO).clicked() {
model.go_to(channel, row);
}
});
if offered.iter().any(|choice| choice.wider()) {
ui.colored_label(theme::tone_ink(&crate::reply::convs::Tone::Weak), WIDER);
ui.horizontal_wrapped(|ui| {
for choice in offered.iter().filter(|choice| choice.wider()) {
seat(ui, choice);
}
});
}
if let Some(choice) = taken {
crate::ui::ask::answer(model, channel, row, choice);
}
}
pub fn headline(row: &QueueRow) -> String {
let mut said = vec![format!(
"{} on {} {}",
row.display,
row.workspace,
crate::ui::convs::age(row.age_secs)
)];
if row.pending > 0 {
said.push(format!("{} under it", row.pending));
}
said.join(" ")
}
pub fn mark(row: &QueueRow) -> (String, egui::Color32) {
crate::ui::convs::glyph(&row.state, row.uncertain, true)
}
pub fn flagged(row: &QueueRow) -> Option<String> {
let flag = row.flag.as_ref()?;
Some(format!("flagged {} — {}", flag.at, flag.reason))
}
pub fn parked(row: &QueueRow) -> Option<String> {
let held = row.held.as_ref()?;
Some(format!(
"waiting for your approval: {} — {}",
held.tool, held.reason
))
}
pub fn signalled(row: &QueueRow) -> Option<String> {
row.why(" ")
}
#[cfg(test)]
mod tests;