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";
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 wall = String::new();
if let Some(fleet) = model.fleet.as_mut() {
wall.clone_from(&fleet.at.address);
ui.horizontal_wrapped(|ui| {
if ui.button(FEWER).clicked() {
fleet.spread = fleet.spread.saturating_sub(1).max(LEAST);
}
ui.label(fleet.spread.to_string());
if ui.button(MORE).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(&wall, 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 = ui.add_enabled(!summary.is_empty(), egui::Button::new(ACCEPT));
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 = ui.button(RELEASE);
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 = ui.add_enabled(
!goal.is_empty(),
egui::Button::new(format!("{SPREAD} {}", fleet.spread)),
);
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;