use std::collections::HashMap;
use ratatui::{
Frame,
layout::Rect,
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Clear, Paragraph},
};
use unicode_width::UnicodeWidthStr;
use super::Component;
use crate::{action::Action, state::ThemeName, theme};
pub struct Toast {
message: Option<String>,
ticks: u8,
theme_name: ThemeName,
color_overrides: HashMap<String, Color>,
}
const VISIBILITY_TICKS: u8 = 12;
impl Toast {
pub fn new(theme_name: ThemeName, color_overrides: HashMap<String, Color>) -> Self {
Self {
message: None,
ticks: 0,
theme_name,
color_overrides,
}
}
pub fn set_theme(&mut self, theme_name: ThemeName, color_overrides: HashMap<String, Color>) {
self.theme_name = theme_name;
self.color_overrides = color_overrides;
}
}
impl Component for Toast {
fn update(&mut self, action: Action) -> color_eyre::Result<Option<Action>> {
match action {
Action::Flash(msg) => {
self.message = Some(msg);
self.ticks = VISIBILITY_TICKS;
}
Action::Tick if self.ticks > 0 => {
self.ticks -= 1;
if self.ticks == 0 {
self.message = None;
}
}
_ => {}
}
Ok(None)
}
fn draw(&mut self, f: &mut Frame, _area: Rect) -> color_eyre::Result<()> {
let Some(ref msg) = self.message else {
return Ok(());
};
let theme = theme::Theme::for_name_with_overrides(self.theme_name, &self.color_overrides);
let area = f.area();
let prefix = "▶ ";
let content_w = prefix.width() + msg.width() + 1;
let box_w = (content_w + 2).min(area.width.saturating_sub(2) as usize);
let box_h: u16 = 3;
if area.width < box_w as u16 + 2 || area.height < box_h + 2 {
return Ok(());
}
let x = area.width.saturating_sub(box_w as u16 + 1);
let y = area.height.saturating_sub(box_h + 1);
let rect = Rect::new(x, y, box_w as u16, box_h);
f.render_widget(Clear, rect);
let block = Block::default()
.borders(Borders::ALL)
.border_type(theme.chrome.border_type())
.border_style(Style::default().fg(theme.border_unfocused).bg(theme.bg_alt))
.style(Style::default().bg(theme.bg_alt));
let text = Line::from(vec![
Span::styled(
prefix.to_string(),
Style::default().fg(theme.shuire).bg(theme.bg_alt),
),
Span::styled(
msg.to_string(),
Style::default()
.fg(theme.context_fg)
.bg(theme.bg_alt)
.add_modifier(Modifier::BOLD),
),
]);
let para = Paragraph::new(text).block(block);
f.render_widget(para, rect);
Ok(())
}
}