pub mod repeat;
pub mod stats;
pub mod typing;
use std::cell::RefCell;
use std::rc::Rc;
use ratatui::{
Frame,
crossterm::event::KeyEvent,
layout::Rect,
style::{Color, Style, Stylize},
text::{Line, Span, Text},
widgets::{Paragraph, block::Title},
};
use crate::{
config::{TukaiConfig, TukaiLayout, TukaiLayoutColorTypeEnum},
storage::storage_handler::StorageHandler,
};
#[derive(PartialEq, Hash, Eq, Debug)]
pub enum ActiveScreenEnum {
Typing,
Repeat,
Stats,
}
#[allow(unused)]
pub trait ToDark {
fn to_dark(self) -> Color;
}
impl ToDark for Color {
fn to_dark(self) -> Color {
match self {
Color::Rgb(r, g, b) => {
let darkened_r = (r as f32 * (1.0 - 0.2)) as u8;
let darkened_g = (g as f32 * (1.0 - 0.2)) as u8;
let darkened_b = (b as f32 * (1.0 - 0.2)) as u8;
Color::Rgb(darkened_r, darkened_g, darkened_b)
}
_ => self,
}
}
}
pub struct Instruction<'a> {
title: &'a str,
shortcut: &'a str,
color_type: TukaiLayoutColorTypeEnum,
}
impl<'a> Instruction<'a> {
pub fn new(title: &'a str, shortcut: &'a str, color_type: TukaiLayoutColorTypeEnum) -> Self {
Self {
title,
shortcut,
color_type,
}
}
}
pub struct InstructionWidget<'a> {
layout: &'a TukaiLayout,
instructions: Vec<Instruction<'a>>,
}
impl<'a> InstructionWidget<'a> {
pub fn new(layout: &'a TukaiLayout) -> Self {
Self {
layout,
instructions: Vec::new(),
}
}
fn get_instruction_color(&self, _color_type: &TukaiLayoutColorTypeEnum) -> Color {
self.layout.get_primary_color()
}
pub fn add_instruction(&mut self, instruction: Instruction<'a>) {
self.instructions.push(instruction);
}
pub fn get_paragraph(&self) -> Paragraph {
let instructions_spans = self
.instructions
.iter()
.enumerate()
.flat_map(|(index, instruction)| {
let color = self.get_instruction_color(&instruction.color_type);
vec![
Span::from(format!(" {}", instruction.title)).style(Style::default().fg(color.to_dark())),
Span::from(format!(
" {}{}",
instruction.shortcut,
if index != self.instructions.len() - 1 {
" |"
} else {
""
}
))
.style(Style::default().fg(color).bold()),
]
})
.collect::<Vec<Span>>();
Paragraph::new(Text::from(Line::from(instructions_spans)))
}
}
pub trait Screen {
fn increment_time_secs(&mut self);
fn get_config(&self) -> &Rc<RefCell<TukaiConfig>>;
fn get_screen_name(&self) -> String;
fn get_remaining_time(&self) -> usize;
fn get_previous_screen(&self) -> Option<ActiveScreenEnum> {
None
}
fn get_next_screen(&self) -> Option<ActiveScreenEnum> {
None
}
fn stop(&mut self, _storage_handler: &mut StorageHandler) {}
fn get_title<'a>(&self) -> Title<'a> {
let app_config = self.get_config().borrow();
let app_layout = app_config.get_layout();
Title::from(format!(
" tukai v{} 》{} 》{} 》{} ",
env!("CARGO_PKG_VERSION"),
app_layout.get_active_layout_name(),
app_config.get_language().get_lang_code(),
self.get_screen_name()
))
}
fn reset(&mut self);
fn handle_events(&mut self, key: KeyEvent) -> bool;
fn is_running(&self) -> bool {
false
}
fn is_popup_visible(&self) -> bool {
false
}
fn render_instructions(&self, frame: &mut Frame, area: Rect);
fn render(&self, frame: &mut Frame, area: Rect);
fn render_popup(&self, frame: &mut Frame);
#[allow(unused_variables)]
fn handle_control_events(&mut self, key_event: KeyEvent) -> bool {
false
}
}