use crate::app::App;
use ratatui::{
Frame,
layout::{Constraint, Flex, Layout, Rect},
style::{Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Clear, Paragraph, Wrap},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConfirmPending {
CheckoutBranch {
repo: String,
number: u32,
branch: String,
},
MergePullRequest {
repo: String,
number: u32,
method: crate::github::mutations::MergeMethod,
expected_head_sha: String,
},
}
#[derive(Debug, Clone)]
pub struct Confirm {
pub title: String,
pub prompt: String,
pub pending_action: ConfirmPending,
}
pub fn draw(f: &mut Frame, app: &App) {
let Some(confirm) = &app.confirm else {
return;
};
let p = &app.palette;
let area = centered_rect(64, 9, f.area());
let title = format!(" {} ", confirm.title);
let block = Block::default()
.title(title.as_str())
.borders(Borders::ALL)
.border_style(Style::default().fg(p.border_focused))
.style(Style::default().bg(p.help_bg));
let hint_yes =
Span::styled("[y] yes", Style::default().fg(p.success).add_modifier(Modifier::BOLD));
let hint_no =
Span::styled("[n/N] cancel", Style::default().fg(p.dim).add_modifier(Modifier::BOLD));
let lines = vec![
Line::from(""),
Line::from(Span::styled(confirm.prompt.as_str(), Style::default().fg(p.foreground))),
Line::from(""),
Line::from(vec![Span::raw(" "), hint_yes, Span::raw(" "), hint_no]),
];
let paragraph = Paragraph::new(lines).block(block).wrap(Wrap { trim: false });
f.render_widget(Clear, area);
f.render_widget(paragraph, area);
}
fn centered_rect(width: u16, height: u16, area: Rect) -> Rect {
let w = width.min(area.width);
let h = height.min(area.height);
let [_, center_v, _] =
Layout::vertical([Constraint::Fill(1), Constraint::Length(h), Constraint::Fill(1)])
.flex(Flex::Center)
.areas(area);
let [_, center_h, _] =
Layout::horizontal([Constraint::Fill(1), Constraint::Length(w), Constraint::Fill(1)])
.flex(Flex::Center)
.areas(center_v);
center_h
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn confirm_pending_clone_eq() {
let pending = ConfirmPending::CheckoutBranch {
repo: "owner/repo".to_owned(),
number: 42,
branch: "feat/my-feature".to_owned(),
};
assert_eq!(pending.clone(), pending);
}
#[test]
fn confirm_fields_accessible() {
let c = Confirm {
title: "Checkout branch".to_owned(),
prompt: "Checkout `feat/foo` in /home/user/project?".to_owned(),
pending_action: ConfirmPending::CheckoutBranch {
repo: "owner/repo".to_owned(),
number: 1,
branch: "feat/foo".to_owned(),
},
};
assert_eq!(c.title, "Checkout branch");
assert!(c.prompt.contains("feat/foo"));
matches!(c.pending_action, ConfirmPending::CheckoutBranch { .. });
}
}