From 6b8b4ef355da35d5c57c0010c106a4d47ab7768b Mon Sep 17 00:00:00 2001 From: "alterwain@protonmail.com" Date: Mon, 17 Feb 2025 16:09:56 +0300 Subject: [PATCH] Small upd --- src/component.rs | 74 ++++++++++++++++++++++++++++++++++++++++ src/file_system.rs | 84 ++++++++++++++++++++++++++-------------------- src/main.rs | 1 + 3 files changed, 122 insertions(+), 37 deletions(-) create mode 100644 src/component.rs diff --git a/src/component.rs b/src/component.rs new file mode 100644 index 0000000..7f7333a --- /dev/null +++ b/src/component.rs @@ -0,0 +1,74 @@ +pub mod table { + use ratatui::layout::{Constraint, Rect}; + use ratatui::prelude::{Color, Style}; + use ratatui::widgets::{Block, Borders, Row, Table}; + use ratatui::Frame; + + pub struct SmartTable { + header: Vec, + data: Vec>, + constraints: Vec, + selected_row: i32, + title: String, + } + + impl SmartTable { + pub fn new(header: Vec, constraints: Vec) -> Self { + Self { + header, + data: Vec::new(), + constraints, + selected_row: 0, + title: String::new(), + } + } + + pub fn set_data(&mut self, data: Vec>) { + self.data = data; + } + + pub fn set_title(&mut self, title: String) { + self.title = title; + } + + pub fn previous_row(&mut self) { + self.selected_row = (self.selected_row - 1).max(0); + } + + pub fn next_row(&mut self) { + self.selected_row = (self.selected_row + 1).min(self.data.len() as i32 - 1); + } + + pub fn selected_row(&self) -> usize { + self.selected_row as usize + } + + pub fn render(&self, frame: &mut Frame, area: Rect) { + let mut v = vec![Row::new(self.header.clone()).style(Style::default().fg(Color::Gray))]; + + for (i, entry) in self.data.iter().enumerate() { + v.push( + Row::new(entry.clone()).style(if self.selected_row as usize == i { + Style::default().bg(Color::LightBlue).fg(Color::White) + } else { + Style::default() + }), + ); + } + + if self.selected_row as usize > area.rows().count() - 4 { + v = v[(self.selected_row as usize - (area.rows().count() - 4))..].to_vec(); + } + + let table = Table::new(v, self.constraints.clone()) + .block( + Block::default() + .borders(Borders::ALL) + .title(self.title.as_ref()), + ) + .style(Style::default().fg(Color::Black)); + + frame.render_widget(table, area); + } + } +} diff --git a/src/file_system.rs b/src/file_system.rs index ea6ae84..898ec69 100644 --- a/src/file_system.rs +++ b/src/file_system.rs @@ -1,8 +1,10 @@ +use crate::component::table::SmartTable; use crate::{screen::AppScreen, theme::Theme}; use chrono::{DateTime, Utc}; +use crossterm::event::KeyCode; use ratatui::layout::{Constraint, Direction, Layout, Rect}; -use ratatui::prelude::{Color, Line, Style, Stylize}; -use ratatui::widgets::{Block, Borders, Paragraph, Row, Table}; +use ratatui::prelude::{Line, Stylize}; +use ratatui::widgets::Paragraph; use ratatui::Frame; use std::cmp::Ordering; use std::fs::DirEntry; @@ -10,19 +12,38 @@ use std::os::unix::fs::MetadataExt; use std::path::PathBuf; pub struct FileSystem { - dir: Vec, + table: SmartTable, } impl Default for FileSystem { fn default() -> Self { - let mut a = Self { dir: Vec::new() }; + let table = SmartTable::new( + ["Name", "Type", "Size", "Modified"] + .iter_mut() + .map(|s| s.to_string()) + .collect(), + vec![ + Constraint::Percentage(50), + Constraint::Length(5), + Constraint::Percentage(20), + Constraint::Percentage(30), + ], + ); + + let mut a = Self { table }; a.get_path(dirs::document_dir().unwrap()); a } } impl AppScreen for FileSystem { - fn handle_key_event(&mut self, key_event: crossterm::event::KeyEvent) {} + fn handle_key_event(&mut self, key_event: crossterm::event::KeyEvent) { + match key_event.code { + KeyCode::Up => self.table.previous_row(), + KeyCode::Down => self.table.next_row(), + _ => {} + } + } fn render(&self, frame: &mut ratatui::Frame, theme: &Theme) { let chunks = Layout::default() @@ -58,52 +79,41 @@ impl AppScreen for FileSystem { impl FileSystem { fn get_path(&mut self, p: PathBuf) { - let paths = std::fs::read_dir(p).unwrap(); - self.dir = paths + let paths = std::fs::read_dir(&p).unwrap(); + let mut dir = paths .filter_map(|res| res.ok()) .filter(|p| p.path().extension().map_or(false, |ext| ext == "mp3") || p.path().is_dir()) - .collect(); - self.dir.sort_by(|a, b| { + .collect::>(); + dir.sort_by(|a, _b| { if a.file_type().unwrap().is_dir() { Ordering::Less } else { Ordering::Greater } }); - } - fn render_main(&self, frame: &mut Frame, area: Rect) { - let mut v = vec![Row::new(vec!["Name", "Type", "Size", "Modified"]) - .style(Style::default().fg(Color::Gray))]; - - for entry in self.dir.iter() { - let datetime: DateTime = entry.metadata().unwrap().modified().unwrap().into(); - let datetime = datetime.format("%d/%m/%Y %T").to_string(); - let size = entry.metadata().unwrap().size().to_string(); - let file_type = entry.file_type().unwrap().is_file().to_string(); - v.push( - Row::new(vec![ + let dir = dir + .iter() + .map(|entry| { + let datetime: DateTime = entry.metadata().unwrap().modified().unwrap().into(); + let datetime = datetime.format("%d/%m/%Y %T").to_string(); + let size = entry.metadata().unwrap().size().to_string(); + let file_type = entry.file_type().unwrap().is_file().to_string(); + vec![ entry.file_name().to_str().unwrap().to_string(), file_type, size, datetime, - ]) - .style(Style::default()), - ); - } + ] + }) + .collect::>>(); - let table = Table::new( - v, - &[ - Constraint::Percentage(50), - Constraint::Length(5), - Constraint::Percentage(20), - Constraint::Percentage(30), - ], - ) - .block(Block::default().borders(Borders::ALL).title(" Documents ")) - .style(Style::default().fg(Color::Black)); + self.table.set_data(dir); + self.table + .set_title(p.iter().last().unwrap().to_str().unwrap().to_string()); + } - frame.render_widget(table, area); + fn render_main(&self, frame: &mut Frame, area: Rect) { + self.table.render(frame, area); } } diff --git a/src/main.rs b/src/main.rs index bebbb5b..c686579 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ use tokio::sync::mpsc::{self, Receiver, UnboundedSender}; use tokio_util::sync::CancellationToken; use wait_screen::WaitScreen; +mod component; mod config; mod dlp; mod file_system;