use crate::reply::proposals::Proposal;
use crate::ui::{Model, Proposing, keys, theme};
use crate::verbs::proposals::VERDICTS;
pub const HEADING: &str = "staged proposals";
pub const NOT_ANSWERED: &str = "waiting to hear what a reviewer has staged";
pub const NOTHING_STAGED: &str = "nothing is staged for this wall";
pub const NOT_WHOLE: &str = "waiting to hear this proposal whole";
pub const GONE: &str = "no longer staged — it was settled, or its branch went";
pub const CLOSE: &str = "leave it staged";
pub const ARM: &str = "the proposal's own id";
pub const NOT_ARMED: &str = "not armed — type the id above, exactly";
pub const ARMED: &str = "armed";
pub const ASKED: &str = "asked — waiting for the engine";
pub const VERDICTS_DO: &str = "accept moves the lineage onto it and every conversation on \
that lineage picks it up at its next step; reject deletes \
the staging branch";
const ARM_WIDTH: f32 = 200.0;
pub(super) fn render(ui: &mut egui::Ui, model: &mut Model) {
ui.label(HEADING);
let named = model.named_proposal();
match model.proposals.clone() {
None => {
ui.label(NOT_ANSWERED);
}
Some(staged) if staged.rows.is_empty() => {
ui.label(NOTHING_STAGED);
}
Some(staged) => {
for row in &staged.rows {
listed(ui, model, row, named.as_ref());
}
}
}
if let Some(named) = named {
ui.separator();
whole(ui, model, &named);
}
}
pub fn line(row: &Proposal) -> String {
format!(
"{} — moves {} — {} — {}",
row.standing(),
row.moves(),
row.diffstat,
row.subject
)
}
fn listed(ui: &mut egui::Ui, model: &mut Model, row: &Proposal, named: Option<&Proposing>) {
ui.horizontal_wrapped(|ui| {
let chosen = named.is_some_and(|held| held.id == row.id);
let control = ui.selectable_label(chosen, &row.id);
crate::ui::act::tag(&control, &[crate::verbs::PROPOSALS.word]);
if control.clicked() {
model.name_proposal(&row.id);
}
});
ui.colored_label(theme::tone_ink(&crate::reply::convs::Tone::Weak), line(row));
}
fn whole(ui: &mut egui::Ui, model: &mut Model, named: &Proposing) {
let staged = model.staged_proposal(&named.id);
ui.label(&named.id);
match (
&staged,
model.proposals.as_ref().and_then(|held| held.whole.clone()),
) {
(None, _) => {
ui.colored_label(theme::NOTICE, GONE);
}
(Some(_), None) => {
ui.label(NOT_WHOLE);
}
(Some(_), Some(text)) => verbatim(ui, &named.id, &text),
}
ui.colored_label(theme::NOTICE, VERDICTS_DO);
if let Some(typed) = model.verdict_box() {
ui.horizontal_wrapped(|ui| {
ui.add(
egui::TextEdit::singleline(typed)
.id(egui::Id::new(keys::VERDICT_ID))
.desired_width(ARM_WIDTH)
.hint_text(ARM),
);
});
}
let live = staged.is_some() && model.named_proposal().is_some_and(|held| held.armed());
ui.horizontal_wrapped(|ui| {
if ui.button(CLOSE).clicked() {
model.unname_proposal();
}
for verdict in VERDICTS {
let spend = ui.add_enabled(live, egui::Button::new(verdict));
crate::ui::act::tag(&spend, &[crate::verbs::PROPOSAL.word]);
if spend.clicked() {
model.settle_proposal(verdict);
}
}
});
if let Some(held) = model.named_proposal() {
ui.colored_label(theme::NOTICE, said(&held));
}
}
fn verbatim(ui: &mut egui::Ui, id: &str, text: &str) {
egui::ScrollArea::horizontal().id_salt(id).show(ui, |ui| {
ui.add(
egui::Label::new(egui::RichText::new(text).monospace())
.wrap_mode(egui::TextWrapMode::Extend),
);
});
}
pub fn said(held: &Proposing) -> String {
if held.posted {
ASKED.to_owned()
} else if held.armed() {
ARMED.to_owned()
} else {
NOT_ARMED.to_owned()
}
}
#[cfg(test)]
mod tests;