use serde_json::Value;
use crate::reply::diff::Diff;
use crate::ui::model::Spread;
use crate::ui::{Model, theme};
pub const SPREAD: &str = "spread it over";
pub const ACCEPT: &str = "accept this one";
pub const RELEASE: &str = "release its worktree";
pub const GOAL_HINT: &str = "what each candidate is for";
pub const SUMMARY_HINT: &str = "the delivery subject";
pub const FEWER: &str = "−1";
pub const MORE: &str = "+1";
pub const FEWER_HELP: &str = "one candidate fewer, never below two";
pub const MORE_HELP: &str = "one candidate more";
pub const SPREAD_HELP: &str =
"starts that many candidates on this ball at once, each on the goal above";
pub const ACCEPT_HELP: &str =
"delivers this candidate's work under the subject above; the rest are released";
pub const RELEASE_HELP: &str = "discards this candidate's worktree";
const WIDTH: f32 = 260.0;
const LEAST: u64 = 2;
pub(super) fn render(ui: &mut egui::Ui, model: &mut Model, rows: &[Diff]) {
let mut act: Option<Value> = None;
let mut spread: Option<(Spread, String)> = None;
let mut workspace = String::new();
if let Some(fleet) = model.fleet.as_mut() {
workspace.clone_from(&fleet.at.address);
ui.horizontal_wrapped(|ui| {
if theme::paint::button(ui, FEWER, true, FEWER_HELP).clicked() {
fleet.spread = fleet.spread.saturating_sub(1).max(LEAST);
}
ui.label(fleet.spread.to_string());
if theme::paint::button(ui, MORE, true, MORE_HELP).clicked() {
fleet.spread = fleet.spread.saturating_add(1);
}
ui.add(
egui::TextEdit::singleline(&mut fleet.goal)
.id(egui::Id::new(crate::ui::keys::FAN_GOAL_ID))
.desired_width(WIDTH)
.hint_text(GOAL_HINT),
);
ui.add(
egui::TextEdit::singleline(&mut fleet.summary)
.id(egui::Id::new(crate::ui::keys::SUMMARY_ID))
.desired_width(WIDTH)
.hint_text(SUMMARY_HINT),
);
});
for row in rows {
ui.separator();
ui.label(super::changed(row));
for file in &row.files {
ui.colored_label(
theme::tone_ink(&crate::reply::convs::Tone::Weak),
super::churn(file),
);
}
match &row.handle {
Some(handle) => {
if let Some(fired) = candidate(ui, fleet, row, handle) {
act = Some(fired);
}
}
None => {
if let Some(fired) = claim(ui, fleet, row) {
spread = Some(fired);
}
}
}
}
}
if let Some(envelope) = act {
model.post_candidate(envelope);
}
if let Some((over, goal)) = spread {
model.stage_spread(&workspace, over, &goal);
}
}
fn candidate(
ui: &mut egui::Ui,
fleet: &crate::ui::model::Fleet,
row: &Diff,
handle: &str,
) -> Option<Value> {
let mut fired = None;
ui.horizontal_wrapped(|ui| {
let summary = fleet.summary.trim();
let take = theme::paint::button(ui, ACCEPT, !summary.is_empty(), ACCEPT_HELP);
crate::ui::act::tag(&take, &[crate::verbs::DELIVER]);
if take.clicked() {
fired = Some(crate::verbs::deliver(
row.ball_id.clone(),
row.project.clone(),
handle.to_owned(),
summary.to_owned(),
));
}
let drop = theme::paint::button(ui, RELEASE, true, RELEASE_HELP);
crate::ui::act::tag(&drop, &[crate::verbs::RETIRE]);
if drop.clicked() {
fired = Some(crate::verbs::retire(
row.ball_id.clone(),
row.project.clone(),
handle.to_owned(),
));
}
});
fired
}
fn claim(
ui: &mut egui::Ui,
fleet: &crate::ui::model::Fleet,
row: &Diff,
) -> Option<(Spread, String)> {
let mut fired = None;
ui.horizontal_wrapped(|ui| {
let goal = fleet.goal.trim();
let over = theme::paint::button(
ui,
&format!("{SPREAD} {}", fleet.spread),
!goal.is_empty(),
SPREAD_HELP,
);
crate::ui::act::tag(&over, &[crate::verbs::PREPARE, crate::verbs::FAN]);
if over.clicked() {
fired = Some((
Spread {
ball: row.ball_id.clone(),
project: row.project.clone(),
n: fleet.spread,
},
goal.to_owned(),
));
}
});
fired
}
#[cfg(test)]
mod tests;