use ratatui::{Frame, prelude::Rect, style::Style, widgets::Block};
use crate::state::AppState;
use crate::theme::theme;
mod alert;
mod announcement;
mod common;
mod confirm;
mod foreign_overlap;
mod help;
mod misc;
mod news;
mod password;
mod post_summary;
mod preflight;
mod preflight_exec;
mod renderer;
mod system_update;
mod updates;
pub fn render_modals(f: &mut Frame, app: &mut AppState, area: Rect) {
let th = theme();
if !matches!(app.modal, crate::state::Modal::None) {
let scrim = Block::default().style(Style::default().bg(th.mantle));
f.render_widget(scrim, area);
}
let modal = std::mem::replace(&mut app.modal, crate::state::Modal::None);
app.modal = renderer::render_modal(modal, f, app, area);
}
#[cfg(test)]
mod tests {
#[test]
fn modals_set_rects_and_render_variants() {
use ratatui::{Terminal, backend::TestBackend};
let backend = TestBackend::new(100, 28);
let mut term = Terminal::new(backend).expect("Failed to create terminal for test");
let mut app = crate::state::AppState {
modal: crate::state::Modal::Alert {
message: "Test".into(),
},
..Default::default()
};
term.draw(|f| {
let area = f.area();
super::render_modals(f, &mut app, area);
})
.expect("Failed to render Alert modal");
app.modal = crate::state::Modal::ConfirmInstall { items: vec![] };
term.draw(|f| {
let area = f.area();
super::render_modals(f, &mut app, area);
})
.expect("Failed to render ConfirmInstall modal");
app.modal = crate::state::Modal::ConfirmAurVote {
pkgbase: "pacsea-bin".to_string(),
action: crate::sources::VoteAction::Vote,
message: "Confirm AUR vote".to_string(),
};
term.draw(|f| {
let area = f.area();
super::render_modals(f, &mut app, area);
})
.expect("Failed to render ConfirmAurVote modal");
app.modal = crate::state::Modal::ConfirmRemove {
items: vec![crate::state::PackageItem {
name: "glibc".into(),
version: "1".into(),
description: String::new(),
source: crate::state::Source::Official {
repo: "core".into(),
arch: "x86_64".into(),
},
popularity: None,
out_of_date: None,
orphaned: false,
}],
};
term.draw(|f| {
let area = f.area();
super::render_modals(f, &mut app, area);
})
.expect("Failed to render ConfirmRemove modal");
app.modal = crate::state::Modal::Help;
term.draw(|f| {
let area = f.area();
super::render_modals(f, &mut app, area);
})
.expect("Failed to render Help modal");
assert!(app.help_rect.is_some());
app.modal = crate::state::Modal::News {
items: vec![crate::state::types::NewsFeedItem {
id: "test".to_string(),
date: "2025-10-11".into(),
title: "Test".into(),
summary: None,
url: Some(String::new()),
source: crate::state::types::NewsFeedSource::ArchNews,
severity: None,
packages: Vec::new(),
}],
selected: 0,
scroll: 0,
};
term.draw(|f| {
let area = f.area();
super::render_modals(f, &mut app, area);
})
.expect("Failed to render News modal");
assert!(app.news_rect.is_some());
assert!(app.news_list_rect.is_some());
}
}