shuvarie 0.1.0

Blazingly fast AI coding TUI for chivalrous people
use ratatui::layout::Alignment;
use ratatui::prelude::*;
use ratatui::widgets::{Clear, Paragraph};
use termina::event::{KeyCode, KeyEvent, Modifiers};

use super::add_provider::centered_rect;
use super::theme;

pub enum ConfirmQuitMessage {
    Confirm,
    Cancel,
}

pub enum ConfirmQuitEffect {
    Confirm,
    Cancel,
}

pub struct ConfirmQuit {
    pub open: bool,
}

impl ConfirmQuit {
    pub fn new() -> Self {
        Self { open: false }
    }

    pub fn open(&mut self) {
        self.open = true;
    }

    pub fn close(&mut self) {
        self.open = false;
    }

    pub fn map_event(&self, key: &KeyEvent) -> Option<ConfirmQuitMessage> {
        if key.modifiers.contains(Modifiers::CONTROL) && key.code == KeyCode::Char('c') {
            return Some(ConfirmQuitMessage::Confirm);
        }
        match key.code {
            KeyCode::Enter | KeyCode::Char('y') | KeyCode::Char('Y') => {
                Some(ConfirmQuitMessage::Confirm)
            }
            KeyCode::Escape | KeyCode::Char('n') | KeyCode::Char('N') => {
                Some(ConfirmQuitMessage::Cancel)
            }
            _ => None,
        }
    }

    pub fn update(&mut self, msg: ConfirmQuitMessage) -> Option<ConfirmQuitEffect> {
        match msg {
            ConfirmQuitMessage::Confirm => {
                self.close();
                Some(ConfirmQuitEffect::Confirm)
            }
            ConfirmQuitMessage::Cancel => {
                self.close();
                Some(ConfirmQuitEffect::Cancel)
            }
        }
    }

    pub fn view(&self, frame: &mut Frame<'_>, area: Rect) {
        if !self.open {
            return;
        }
        let popup = centered_rect(45, 25, area);
        frame.render_widget(Clear, popup);
        let block = theme::overlay_block("Quit?");
        let inner = block.inner(popup);
        frame.render_widget(block, popup);

        let lines = vec![
            Line::from(""),
            Line::from("Are you sure you want to quit?")
                .style(Style::new().fg(theme::text()))
                .alignment(Alignment::Center),
            Line::from(""),
            Line::from(""),
        ];

        let content_width = lines
            .iter()
            .map(|l| l.width() as u16)
            .max()
            .unwrap_or(0)
            .min(inner.width);
        let x = inner.x + (inner.width.saturating_sub(content_width)) / 2;
        let text_area = Rect::new(x, inner.y, content_width, inner.height.saturating_sub(1));

        frame.render_widget(Paragraph::new(lines).alignment(Alignment::Left), text_area);

        frame.render_widget(
            Paragraph::new(theme::help_line(&[
                ("Enter", "confirm"),
                ("Ctrl+C", "confirm"),
                ("Esc", "cancel"),
            ]))
            .fg(theme::text_muted())
            .alignment(Alignment::Center),
            Rect::new(inner.x, inner.bottom().saturating_sub(1), inner.width, 1),
        );
    }
}

impl Default for ConfirmQuit {
    fn default() -> Self {
        Self::new()
    }
}