use crate::reply::board::BoardRow;
use crate::ui::{Model, theme};
pub use rows::{binding, cost, gated, headline, held, placed, running, worked};
pub mod acts;
mod rows;
pub mod wall;
pub const OPEN: &str = "the board…";
pub const CLOSE: &str = "done";
pub const HEADING: &str = "the board";
pub const NOT_ANSWERED: &str = "waiting to hear what is on the board";
pub const NOTHING: &str = "no ball is on any board here";
pub const BINDINGS: &str = "every ball⇄workspace binding";
pub fn render(ui: &mut egui::Ui, model: &mut Model) -> bool {
if !model.boarding() {
return false;
}
ui.heading(HEADING);
ui.horizontal_wrapped(|ui| {
if ui.button(CLOSE).clicked() {
model.close_lookup();
}
});
ui.separator();
let columns = model.columns.clone();
let bindings = model.bindings.clone();
let mut fired: Option<(crate::ui::Channel, serde_json::Value)> = None;
egui::ScrollArea::vertical()
.id_salt(HEADING)
.auto_shrink(false)
.show(ui, |ui| {
if columns.is_empty() && bindings.is_empty() {
ui.label(NOT_ANSWERED);
} else if empty(&columns, &bindings) {
ui.label(NOTHING);
}
for section in &columns {
if section.board.rows.is_empty() && section.board.fleet.is_empty() {
continue;
}
ui.separator();
ui.label(crate::ui::roster::header(§ion.channel));
for loop_ in §ion.board.fleet {
ui.colored_label(theme::NOTICE, running(loop_));
}
for row in §ion.board.rows {
if let Some(gesture) = live(ui, model, §ion.channel, row) {
fired = Some((section.channel.clone(), gesture));
}
}
}
wall::render(ui, model);
acts::render(ui, model);
for section in &bindings {
if section.rows.is_empty() {
continue;
}
ui.separator();
ui.label(format!(
"{} — {BINDINGS}",
crate::ui::roster::header(§ion.channel)
));
for row in §ion.rows {
ui.label(binding(row));
}
}
});
if let Some((down, gesture)) = fired {
model.post_ball(&down, gesture);
}
true
}
fn empty(columns: &[crate::ui::Columns], bindings: &[crate::ui::Bindings]) -> bool {
columns
.iter()
.all(|section| section.board.rows.is_empty() && section.board.fleet.is_empty())
&& bindings.iter().all(|section| section.rows.is_empty())
}
fn live(
ui: &mut egui::Ui,
model: &Model,
down: &crate::ui::Channel,
row: &BoardRow,
) -> Option<serde_json::Value> {
ui.label(headline(row));
ui.colored_label(
theme::tone_ink(&crate::reply::convs::Tone::Weak),
placed(row),
);
for said in [held(row), gated(row), worked(row)].into_iter().flatten() {
ui.colored_label(theme::tone_ink(&crate::reply::convs::Tone::Weak), said);
}
for (figure, over) in [
(row.spend.as_ref(), "spent"),
(row.rollup.as_ref(), "under it"),
] {
if let Some(figure) = figure {
ui.colored_label(
theme::tone_ink(&crate::reply::convs::Tone::Weak),
format!("{over}: {}", cost(figure)),
);
}
}
let gesture = model.claiming(down, row)?;
let claim = ui.button(acts::CLAIM);
crate::ui::act::tag(&claim, &[crate::verbs::ASSIGN.word]);
claim.clicked().then_some(gesture)
}
#[cfg(test)]
mod tests;