use ratatui::Frame;
use ratatui::layout::{Alignment, Rect};
use ratatui::style::Style;
use ratatui::text::{Line, Span};
use ratatui::widgets::Paragraph;
use super::super::app::{
App, ConfigFocus, FallbackFocus, FallbackHint, FooterAlert, StatusFocus, Tab, fallback_hint,
};
use super::super::theme;
const TAB_NAV: (&str, &str) = ("←→", "tabs");
pub(super) fn draw(frame: &mut Frame<'_>, area: Rect, app: &App) {
let area = inset_x(area, 1);
if let Some(alert) = &app.footer_alert {
draw_alert(frame, area, alert);
return;
}
let has_sub_focus = (app.tab == Tab::Setup && app.config_focus == ConfigFocus::Actions)
|| (app.tab == Tab::Fallback && app.fallback_focus == FallbackFocus::Detail)
|| (app.tab == Tab::Status && app.status.focus == StatusFocus::Detail);
let q_label: &str = if has_sub_focus { "back" } else { "quit" };
let tail: &[(&str, &str)] = match app.tab {
Tab::Overview => &[("⇧↑↓", "reorder"), ("a", "actions"), ("?", "help")],
Tab::Usage => &[
("↑↓", "account"),
("r", "refresh account"),
("a", "actions"),
("?", "help"),
],
Tab::Setup => match app.config_focus {
ConfigFocus::Profiles => &[
("↑↓", "account"),
("↵", "configure"),
("n", "new"),
("a", "actions"),
("?", "help"),
],
ConfigFocus::Actions => &[
("↑↓", "row"),
("↵", "edit / toggle"),
("a", "actions"),
("esc", "back"),
("?", "help"),
],
},
Tab::Config => &[
("↑↓", "row"),
("↵", "cycle / toggle"),
("a", "actions"),
("?", "help"),
],
Tab::Status => match app.status.focus {
StatusFocus::List => &[
("↑↓", "incident"),
("↵", "open"),
("r", "refresh"),
("a", "actions"),
("?", "help"),
],
StatusFocus::Detail => &[
("↑↓", "scroll"),
("a", "actions"),
("esc", "back"),
("?", "help"),
],
},
Tab::Fallback => match fallback_hint(app) {
FallbackHint::Empty => &[("?", "help")],
FallbackHint::ChainMember => &[
("↑↓", "move"),
("⇧↑↓", "reorder = priority"),
("↵", "open"),
("a", "actions"),
("?", "help"),
],
FallbackHint::ChainAdd => &[("↑↓", "move"), ("↵", "add"), ("?", "help")],
FallbackHint::DetailThreshold => &[
("↑↓", "row"),
("+", "raise"),
("-", "lower"),
("↵", "type"),
("a", "actions"),
("esc", "back"),
("?", "help"),
],
FallbackHint::DetailThresholdEdit => {
&[("↵", "save"), ("←→", "caret"), ("esc", "cancel")]
}
FallbackHint::DetailRemove => &[
("↑↓", "row"),
("↵", "remove"),
("a", "actions"),
("esc", "back"),
("?", "help"),
],
FallbackHint::DetailRemoveArmed => {
&[("↵", "confirm remove"), ("esc", "cancel"), ("?", "help")]
}
FallbackHint::DetailAdd => {
&[("↑↓", "pick"), ("↵", "add"), ("esc", "back"), ("?", "help")]
}
},
};
let show_q = !(app.tab == Tab::Fallback
&& matches!(
fallback_hint(app),
FallbackHint::DetailThresholdEdit | FallbackHint::DetailRemoveArmed
));
let mut hints: Vec<(&str, &str)> = std::iter::once(TAB_NAV)
.chain(tail.iter().copied())
.collect();
if show_q {
hints.push(("q", q_label));
}
let mut spans: Vec<Span<'_>> = Vec::new();
for (i, (key, label)) in hints.iter().enumerate() {
if i > 0 {
spans.push(Span::styled(" ", theme::faint()));
}
spans.push(Span::styled(
*key,
Style::default().fg(theme::accent_color()).bold(),
));
spans.push(Span::styled(format!(" {label}"), theme::dim()));
}
frame.render_widget(
Paragraph::new(Line::from(spans))
.style(theme::base())
.alignment(Alignment::Left),
area,
);
}
fn inset_x(area: Rect, pad: u16) -> Rect {
Rect {
x: area.x.saturating_add(pad),
width: area.width.saturating_sub(pad.saturating_mul(2)),
..area
}
}
fn draw_alert(frame: &mut Frame<'_>, area: Rect, alert: &FooterAlert) {
let FooterAlert::Warn(msg) = alert;
let spans = vec![
Span::styled("! ", Style::default().fg(theme::warning_color())),
Span::styled(msg.as_str(), theme::dim()),
];
frame.render_widget(
Paragraph::new(Line::from(spans))
.style(theme::base())
.alignment(Alignment::Left),
area,
);
}