hac-client 0.2.0

your handy API client, on your terminal!
Documentation
use crate::ascii::LOGO_ASCII;
use crate::pages::collection_viewer::collection_store::CollectionStore;
use crate::pages::overlay::make_overlay;
use crate::pages::{Eventful, Renderable};

use std::cell::RefCell;
use std::ops::{Add, Div, Mul, Sub};
use std::rc::Rc;

use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use rand::Rng;
use ratatui::layout::Rect;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::widgets::Paragraph;
use ratatui::Frame;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeleteItemPromptEvent {
    Confirm,
    Cancel,
}

#[derive(Debug)]
pub struct DeleteItemPrompt<'dip> {
    colors: &'dip hac_colors::Colors,
    collection_store: Rc<RefCell<CollectionStore>>,
    logo_idx: usize,
}

impl<'dip> DeleteItemPrompt<'dip> {
    pub fn new(
        colors: &'dip hac_colors::Colors,
        collection_store: Rc<RefCell<CollectionStore>>,
    ) -> Self {
        let logo_idx = rand::thread_rng().gen_range(0..LOGO_ASCII.len());
        DeleteItemPrompt {
            colors,
            logo_idx,
            collection_store,
        }
    }
}

impl Renderable for DeleteItemPrompt<'_> {
    fn draw(&mut self, frame: &mut Frame, _: Rect) -> anyhow::Result<()> {
        make_overlay(self.colors, self.colors.normal.black, 0.1, frame);

        let store = self.collection_store.borrow();
        let Some(hovered_id) = store.get_hovered_request().as_ref().cloned() else {
            unreachable!();
        };
        let Some(collection) = store.get_collection() else {
            unreachable!();
        };
        let collection = collection.borrow();
        let Some(ref requests) = collection.requests else {
            unreachable!();
        };
        let is_dir = requests
            .read()
            .unwrap()
            .iter()
            .find(|req| req.get_id().eq(&hovered_id))
            .is_some_and(|req| req.is_dir());

        let mut lines = if is_dir {
            vec![
                Line::from(
                    "Are you sure you want to delete the directory?".fg(self.colors.normal.red),
                )
                .centered(),
                Line::from("This will delete all the requests inside".fg(self.colors.normal.red))
                    .centered(),
                Line::from(""),
            ]
        } else {
            vec![
                Line::from(
                    "Are you sure you want to delete the request?".fg(self.colors.normal.red),
                )
                .centered(),
                Line::from(""),
            ]
        };

        lines.push(
            Line::from("[Confirm: Enter] [Cancel: Esc]".fg(self.colors.bright.black)).centered(),
        );

        let logo = LOGO_ASCII[self.logo_idx];
        let logo_size = logo.len() as u16;
        let size = frame.size();

        let size = Rect::new(
            size.width.div(2).sub(25),
            size.height
                .div(2)
                .saturating_sub(logo_size.div(2))
                .saturating_sub(3),
            50,
            logo_size.add(7),
        );

        let logo_size = Rect::new(size.x, size.y, size.width, logo_size);
        let logo = logo
            .iter()
            .map(|line| Line::from(line.fg(self.colors.normal.red)).centered())
            .collect::<Vec<_>>();
        frame.render_widget(Paragraph::new(logo), logo_size);

        for (idx, line) in lines.into_iter().enumerate() {
            let y_offset = logo_size.height.add(2).add(idx.mul(1) as u16);
            let line_size = Rect::new(size.x, size.y.add(y_offset), size.width, 1);
            frame.render_widget(Paragraph::new(line), line_size);
        }

        Ok(())
    }
}

impl Eventful for DeleteItemPrompt<'_> {
    type Result = DeleteItemPromptEvent;

    fn handle_key_event(&mut self, key_event: KeyEvent) -> anyhow::Result<Option<Self::Result>> {
        if let (KeyCode::Char('c'), KeyModifiers::CONTROL) = (key_event.code, key_event.modifiers) {
            return Ok(Some(DeleteItemPromptEvent::Cancel));
        }

        match key_event.code {
            KeyCode::Enter => Ok(Some(DeleteItemPromptEvent::Confirm)),
            KeyCode::Esc => Ok(Some(DeleteItemPromptEvent::Cancel)),
            _ => Ok(None),
        }
    }
}