This commit is contained in:
2026-03-08 17:52:16 +01:00
parent 62fb8cd330
commit 5f691c2e2f
7 changed files with 2155 additions and 56 deletions

184
src/app.rs Normal file
View File

@ -0,0 +1,184 @@
use fuzzy_matcher::{FuzzyMatcher, skim::SkimMatcherV2};
use ratatui::widgets::ListState;
use ratatui_image::{picker::Picker, protocol};
use std::path::Path;
#[derive(PartialEq)]
pub enum Mode {
Normal,
Command,
Search,
}
pub struct App {
pub mode: Mode,
pub all_items: Vec<String>,
pub filtered_items: Vec<String>,
pub list_state: ListState,
pub input_buffer: String,
pub should_quit: bool,
pub undo_stack: Vec<(usize, String)>,
pub current_image: Option<protocol::StatefulProtocol>,
pub last_selected_index: Option<usize>,
pub picker: Picker,
}
impl App {
pub fn new() -> Self {
let mut list_state = ListState::default();
list_state.select(Some(0));
let items = vec![
"Ceci est un texte copié.".to_string(),
"https://github.com/ratatui-org/ratatui".to_string(),
"30426b4d-26e0-45af-9fa4-25f4476387a8.jpg".to_string(),
"35789d6a-dea4-46de-90da-aee693a16031.jpg".to_string(),
"fn main() {\n println!(\"Hello\");\n}".to_string(),
];
let picker = Picker::from_query_stdio().unwrap_or_else(|_| Picker::halfblocks());
let mut app = Self {
mode: Mode::Normal,
filtered_items: items.clone(),
all_items: items,
list_state,
input_buffer: String::new(),
should_quit: false,
undo_stack: Vec::new(),
current_image: None,
last_selected_index: None,
picker,
};
app.update_preview();
app
}
pub fn update_search(&mut self) {
if self.input_buffer.is_empty() {
self.filtered_items = self.all_items.clone();
} else {
let matcher = SkimMatcherV2::default();
let mut matched: Vec<(i64, String)> = self
.all_items
.iter()
.filter_map(|item| {
matcher
.fuzzy_match(item, &self.input_buffer)
.map(|score| (score, item.clone()))
})
.collect();
matched.sort_by(|a, b| b.0.cmp(&a.0));
self.filtered_items = matched.into_iter().map(|(_, item)| item).collect();
self.update_preview();
}
self.list_state.select(if self.filtered_items.is_empty() {
None
} else {
Some(0)
});
}
pub fn delete_selected(&mut self) {
if let Some(i) = self.list_state.selected() {
if i < self.filtered_items.len() {
let item_to_remove = self.filtered_items.remove(i);
self.undo_stack.push((i, item_to_remove.clone()));
if let Some(pos) = self.all_items.iter().position(|x| *x == item_to_remove) {
self.all_items.remove(pos);
}
if self.filtered_items.is_empty() {
self.list_state.select(None);
} else if i >= self.filtered_items.len() {
self.list_state.select(Some(self.filtered_items.len() - 1));
}
}
}
self.update_preview();
}
pub fn undo_delete(&mut self) {
if let Some((i, item)) = self.undo_stack.pop() {
self.all_items.insert(i, item.clone());
self.update_search();
self.list_state.select(Some(i));
}
self.update_preview();
}
pub fn update_preview(&mut self) {
let current_index = self.list_state.selected();
if self.last_selected_index == current_index {
return;
}
self.last_selected_index = current_index;
self.current_image = None;
if let Some(selected_text) = self.get_selected_item() {
// To change later with entry type
if selected_text.ends_with(".jpg") || selected_text.ends_with(".png") {
let base_dir = directories::ProjectDirs::from("com", "zefad", "rklipd")
.expect("No home dir")
.data_dir()
.to_path_buf();
let img_path = base_dir.join("images").join(selected_text);
if img_path.exists() {
if let Ok(img) = image::open(&img_path) {
let protocol = self.picker.new_resize_protocol(img);
self.current_image = Some(protocol);
}
}
}
}
}
pub fn next(&mut self) {
if self.filtered_items.is_empty() {
return;
}
let i = match self.list_state.selected() {
Some(i) => {
if i >= self.filtered_items.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.list_state.select(Some(i));
self.update_preview();
}
pub fn previous(&mut self) {
if self.filtered_items.is_empty() {
return;
}
let i = match self.list_state.selected() {
Some(i) => {
if i == 0 {
self.filtered_items.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.list_state.select(Some(i));
self.update_preview();
}
pub fn get_selected_item(&self) -> Option<&String> {
self.list_state.selected().map(|i| &self.filtered_items[i])
}
}