lingora-tui 0.4.14

Lingora is a free and open-source localization management program that analyses fluent translation files highlighting discrepancies between reference and target languages. This application provides a terminal user interface; run as `lingora-tui`.
Documentation
use crossterm::event::{Event, KeyCode, KeyEvent};
use lingora_core::prelude::AuditIssue;
use rat_event::{HandleEvent, Outcome, Regular};
use rat_focus::{FocusFlag, HasFocus};
use ratatui::{prelude::*, widgets::*};

use crate::theme::LingoraTheme;

#[derive(Default, Debug)]
pub struct IssuesState {
    focus_flag: FocusFlag,
    list_state: ListState,
    area: Rect,
}

impl IssuesState {
    fn handle_key_event(&mut self, event: &KeyEvent) -> Outcome {
        match &event.code {
            KeyCode::Up => {
                self.list_state.select_previous();
                Outcome::Unchanged
            }
            KeyCode::Down => {
                self.list_state.select_next();
                Outcome::Unchanged
            }
            _ => Outcome::Continue,
        }
    }
}

impl HasFocus for IssuesState {
    fn build(&self, builder: &mut rat_focus::FocusBuilder) {
        builder.leaf_widget(self);
    }

    fn focus(&self) -> FocusFlag {
        self.focus_flag.clone()
    }

    fn area(&self) -> rat_focus::ratatui::layout::Rect {
        self.area
    }
}

impl HandleEvent<Event, Regular, Outcome> for IssuesState {
    fn handle(&mut self, event: &Event, _qualifier: Regular) -> Outcome {
        if self.focus_flag.is_focused() {
            match event {
                Event::Key(event) => self.handle_key_event(event),
                _ => Outcome::Continue,
            }
        } else {
            Outcome::Continue
        }
    }
}

pub struct Issues<'a> {
    theme: &'a LingoraTheme,
    entries: Vec<AuditIssue>,
}

impl<'a> Issues<'a> {
    pub fn new(theme: &'a LingoraTheme, entries: Vec<AuditIssue>) -> Self {
        Self { theme, entries }
    }
}

impl StatefulWidget for &Issues<'_> {
    type State = IssuesState;

    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)
    where
        Self: Sized,
    {
        state.area = area;

        let list = List::new(self.entries.iter().map(|i| i.to_string()))
            .block(self.theme.focus_block(&state.focus_flag))
            .highlight_style(self.theme.selection())
            .highlight_symbol("ยป ")
            .highlight_spacing(HighlightSpacing::Always);

        StatefulWidget::render(list, area, buf, &mut state.list_state);
    }
}