use ratatui::Frame;
use ratatui::layout::Rect;
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
use crate::tui::app::App;
pub fn render_prefix_confirm(frame: &mut Frame, app: &App, area: Rect) {
let pr = match &app.prefix_rename {
Some(pr) if pr.confirming => pr,
_ => return,
};
let bg = app.theme.background;
let text_color = app.theme.text;
let bright = app.theme.text_bright;
let dim = app.theme.dim;
let highlight = app.theme.highlight;
let warn_color = app.theme.state_color(crate::model::TaskState::Blocked);
let header_style = Style::default()
.fg(highlight)
.bg(bg)
.add_modifier(Modifier::BOLD);
let text_style = Style::default().fg(text_color).bg(bg);
let bright_style = Style::default()
.fg(bright)
.bg(bg)
.add_modifier(Modifier::BOLD);
let warn_style = Style::default().fg(warn_color).bg(bg);
let dim_style = Style::default().fg(dim).bg(bg);
let popup_w: u16 = 50.min(area.width.saturating_sub(2));
let mut lines: Vec<Line> = Vec::new();
lines.push(Line::from(Span::styled(" Rename Prefix", header_style)));
lines.push(Line::from(Span::styled("", text_style)));
lines.push(Line::from(vec![
Span::styled(" ", text_style),
Span::styled(&pr.old_prefix, bright_style),
Span::styled(" \u{2192} ", text_style),
Span::styled(&pr.new_prefix, bright_style),
]));
lines.push(Line::from(Span::styled("", text_style)));
lines.push(Line::from(Span::styled(" This will rename:", text_style)));
lines.push(Line::from(Span::styled(
format!(
" {} task ID{} in {}",
pr.task_id_count,
if pr.task_id_count == 1 { "" } else { "s" },
pr.track_name,
),
text_style,
)));
if pr.dep_ref_count > 0 {
lines.push(Line::from(Span::styled(
format!(
" {} dep reference{} across {} other track{}",
pr.dep_ref_count,
if pr.dep_ref_count == 1 { "" } else { "s" },
pr.affected_track_count,
if pr.affected_track_count == 1 {
""
} else {
"s"
},
),
text_style,
)));
} else {
lines.push(Line::from(Span::styled(
" 0 dep references across other tracks",
text_style,
)));
}
lines.push(Line::from(Span::styled("", text_style)));
lines.push(Line::from(Span::styled(
" This cannot be undone. Use git to revert.",
warn_style,
)));
lines.push(Line::from(Span::styled("", text_style)));
lines.push(Line::from(vec![
Span::styled(" ", text_style),
Span::styled("Enter", dim_style),
Span::styled(" confirm ", text_style),
Span::styled("Esc", dim_style),
Span::styled(" cancel", text_style),
]));
let popup_h = ((lines.len() as u16) + 2).min(area.height.saturating_sub(2));
let overlay_area = centered_rect_fixed(popup_w, popup_h, area);
frame.render_widget(Clear, overlay_area);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(highlight).bg(bg))
.style(Style::default().bg(bg));
let paragraph = Paragraph::new(lines)
.block(block)
.style(Style::default().bg(bg));
frame.render_widget(paragraph, overlay_area);
}
fn centered_rect_fixed(width: u16, height: u16, area: Rect) -> Rect {
let x = area.x + area.width.saturating_sub(width) / 2;
let y = area.y + area.height.saturating_sub(height) / 2;
Rect::new(x, y, width, height)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tui::app::PrefixRenameState;
use crate::tui::render::test_helpers::*;
use insta::assert_snapshot;
#[test]
fn confirm_dialog() {
let mut app = app_with_track(SIMPLE_TRACK_MD);
app.prefix_rename = Some(PrefixRenameState {
track_id: "test".into(),
track_name: "Test Track".into(),
old_prefix: "T".into(),
new_prefix: "TST".into(),
confirming: true,
task_id_count: 4,
dep_ref_count: 2,
affected_track_count: 1,
validation_error: String::new(),
});
let output = render_to_string(TERM_W, TERM_H, |frame, area| {
render_prefix_confirm(frame, &app, area);
});
assert_snapshot!(output);
}
}