clin-rs 0.8.12

Encrypted terminal note-taking app inspired by Obsidian
use crate::app_theme::AppThemeColors;
use crate::keybinds::{CanvasAction, Keybinds};
use crate::pinstar::input::{handle_pinstar_event, handle_pinstar_mouse};
use crate::pinstar::render::draw_pinstar_view;
use crate::pinstar::state::PinstarState;
use crate::storage::Storage;
use crossterm::event::{self, Event};
use ratatui::Terminal;
use ratatui::backend::CrosstermBackend;
use std::io::Stdout;
use std::time::Duration;

pub enum PinstarResult {
    Normal,
    HelpRequested,
}

pub fn run_pinstar_view(
    terminal: &mut Terminal<CrosstermBackend<Stdout>>,
    storage: Storage,
    keybinds: &Keybinds,
    file_id: Option<String>,
    theme: AppThemeColors,
) -> anyhow::Result<PinstarResult> {
    let mut state = if let Some(id) = file_id {
        let path = storage.note_path(&id);
        PinstarState::load(&path)?
    } else {
        anyhow::bail!("No file ID provided for Pinstar view");
    };

    state.footer_hint = format!(
        "{} switch focus · {} back · Arrows select · {} edit · {} save",
        keybinds.canvas_keys_display(CanvasAction::CycleFocus),
        keybinds.canvas_keys_display(CanvasAction::Quit),
        keybinds.canvas_keys_display(CanvasAction::EditOrConnect),
        keybinds.canvas_keys_display(CanvasAction::Save),
    );
    let mut running = true;

    while running {
        terminal.draw(|frame| {
            let full = frame.area();
            let outer = ratatui::layout::Layout::default()
                .direction(ratatui::layout::Direction::Vertical)
                .constraints([
                    ratatui::layout::Constraint::Length(1),
                    ratatui::layout::Constraint::Min(0),
                ])
                .split(full);
            crate::ui::draw_view_title_bar(frame, outer[0], "Canvas", &theme);
            draw_pinstar_view(frame, &mut state, &theme, outer[1]);
        })?;

        if event::poll(Duration::from_millis(100))? {
            let mut pending = true;
            while pending {
                let term_area: ratatui::layout::Rect = terminal.size()?.into();
                let outer = ratatui::layout::Layout::default()
                    .direction(ratatui::layout::Direction::Vertical)
                    .constraints([
                        ratatui::layout::Constraint::Length(1),
                        ratatui::layout::Constraint::Min(0),
                    ])
                    .split(term_area);
                let area = outer[1];
                match event::read()? {
                    Event::Key(key) => {
                        if !handle_pinstar_event(&mut state, key, &mut running, area, keybinds) {}
                    }
                    Event::Mouse(mouse) => {
                        handle_pinstar_mouse(&mut state, mouse, area);
                    }
                    Event::Resize(_, _) => {
                        terminal.autoresize()?;
                        let _ = terminal.clear();
                    }
                    _ => {}
                }
                pending = event::poll(Duration::ZERO)?;
            }
        }
    }

    if state.help_requested {
        Ok(PinstarResult::HelpRequested)
    } else {
        Ok(PinstarResult::Normal)
    }
}