From 68b6d0cfc9c80502a752b101f387b7b7ed7dbe54 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Tue, 24 Mar 2026 15:06:26 +0800 Subject: [PATCH] Ui improvement + delete items from clipboard history --- src/app.rs | 9 +- src/app/pages/clipboard.rs | 164 ++++++++++++++++++++++++++----------- src/app/tile.rs | 4 +- src/app/tile/update.rs | 71 +++++++++++----- src/clipboard.rs | 2 +- src/styles.rs | 14 ++++ 6 files changed, 193 insertions(+), 71 deletions(-) diff --git a/src/app.rs b/src/app.rs index 6267ec52..80eb31aa 100644 --- a/src/app.rs +++ b/src/app.rs @@ -69,6 +69,13 @@ pub enum Move { Forwards(String), } +#[derive(Debug, Clone)] +pub enum Editable { + Create(T), + Delete(T), + Update { old: T, new: T }, +} + /// The message type that iced uses for actions that can do something #[derive(Debug, Clone)] pub enum Message { @@ -95,7 +102,7 @@ pub enum Message { UpdateApps, SetSender(ExtSender), SwitchToPage(Page), - ClipboardHistory(ClipBoardContentType), + EditClipboardHistory(Editable), ChangeFocus(ArrowKey, u32), FileSearchResult(Vec), FileSearchClear, diff --git a/src/app/pages/clipboard.rs b/src/app/pages/clipboard.rs index 798d53dd..742ffa0a 100644 --- a/src/app/pages/clipboard.rs +++ b/src/app/pages/clipboard.rs @@ -6,12 +6,15 @@ use iced::{ Scrollable, image::{Handle, Viewer}, scrollable::{Direction, Scrollbar}, + text::Wrapping, + text_input, }, }; use crate::{ - app::{ToApp, pages::prelude::*}, + app::{Editable, ToApp, pages::prelude::*}, clipboard::ClipBoardContentType, + styles::{delete_button_style, settings_text_input_item_style}, }; /// The clipboard view @@ -30,60 +33,36 @@ pub fn clipboard_view( ) -> Element<'static, Message> { let theme_clone = theme.clone(); let theme_clone_2 = theme.clone(); - let viewport_content: Element<'static, Message> = match clipboard_content - .get(focussed_id as usize) - { - Some(content) => match content { - ClipBoardContentType::Text(txt) => Scrollable::with_direction( - Text::new(txt.to_owned()) - .height(Length::Fill) - .width(Length::Fill) - .align_x(Alignment::Start) - .font(theme.font()) - .size(16), - Direction::Both { - vertical: Scrollbar::new().scroller_width(0.).width(0.), - horizontal: Scrollbar::new().scroller_width(0.).width(0.), - }, - ) - .into(), - - ClipBoardContentType::Image(data) => { - let bytes = data.to_owned_img().into_owned_bytes(); - container( - Viewer::new( - Handle::from_rgba(data.width as u32, data.height as u32, bytes.to_vec()) - .clone(), - ) - .content_fit(ContentFit::ScaleDown) - .scale_step(0.) - .max_scale(1.) - .min_scale(1.), - ) - .padding(10) - .style(|_| container::Style { - border: iced::Border { - color: iced::Color::WHITE, - width: 1., - radius: Radius::new(0.), - }, - ..Default::default() - }) - .width(Length::Fill) - .into() - } - }, - None => Text::new("").into(), - }; - container(Row::from_vec(vec![ + if clipboard_content.is_empty() { + return container( + Text::new("Copy something to use the clipboard history") + .font(theme.font()) + .size(30) + .center() + .wrapping(Wrapping::WordOrGlyph), + ) + .height(Length::Fill) + .width(Length::Fill) + .style(move |_| result_row_container_style(&theme_clone, false)) + .align_x(Alignment::Center) + .align_y(Alignment::Center) + .into(); + } + let viewport_content: Element<'static, Message> = + match clipboard_content.get(focussed_id as usize) { + Some(content) => viewport_content(content, &theme), + None => Text::new("").into(), + }; + container(Row::from_iter([ container( - iced::widget::scrollable( + Scrollable::with_direction( Column::from_iter(clipboard_content.iter().enumerate().map(|(i, content)| { content .to_app() .render(theme.clone(), i as u32, focussed_id) })) .width(WINDOW_WIDTH / 3.), + Direction::Vertical(Scrollbar::hidden()), ) .id("results"), ) @@ -100,3 +79,92 @@ pub fn clipboard_view( .height(280) .into() } + +fn viewport_content(content: &ClipBoardContentType, theme: &Theme) -> Element<'static, Message> { + let viewer: Element<'static, Message> = match content { + ClipBoardContentType::Text(txt) => Scrollable::with_direction( + container( + Text::new(txt.to_owned()) + .height(Length::Fill) + .width(Length::Fill) + .align_x(Alignment::Start) + .font(theme.font()) + .size(16), + ) + .width(Length::Fill) + .height(Length::Fill), + Direction::Both { + vertical: Scrollbar::hidden(), + horizontal: Scrollbar::hidden(), + }, + ) + .height(Length::Fill) + .width(Length::Fill) + .into(), + + ClipBoardContentType::Image(data) => { + let bytes = data.to_owned_img().into_owned_bytes(); + container( + Viewer::new( + Handle::from_rgba(data.width as u32, data.height as u32, bytes.to_vec()) + .clone(), + ) + .content_fit(ContentFit::ScaleDown) + .scale_step(0.) + .max_scale(1.) + .min_scale(1.), + ) + .padding(10) + .style(|_| container::Style { + border: iced::Border { + color: iced::Color::WHITE, + width: 1., + radius: Radius::new(0.), + }, + ..Default::default() + }) + .width(Length::Fill) + .into() + } + }; + + let theme_clone = theme.clone(); + Column::from_iter([ + viewer, + container( + Button::new("Delete") + .on_press(Message::EditClipboardHistory(Editable::Delete( + content.to_owned(), + ))) + .style(move |_, _| delete_button_style(&theme_clone)), + ) + .width(Length::Fill) + .align_x(Alignment::Center) + .padding(10) + .into(), + ]) + .into() +} + +#[allow(unused)] +fn editable_text(text: &str, theme: &Theme) -> Element<'static, Message> { + let text_string = text.to_string(); + let theme_clone = theme.clone(); + container( + text_input("Edit clipboard history text", text) + .on_input(move |input| { + Message::EditClipboardHistory(Editable::Update { + old: ClipBoardContentType::Text(text_string.clone()), + new: ClipBoardContentType::Text(input), + }) + }) + .align_x(Alignment::Start) + .size(16) + .width(Length::Fill) + .style(move |_, _| settings_text_input_item_style(&theme_clone)) + .font(theme.font()), + ) + .height(Length::Fill) + .width(Length::Fill) + .into() +} diff --git a/src/app/tile.rs b/src/app/tile.rs index 556738f7..9ccba3a4 100644 --- a/src/app/tile.rs +++ b/src/app/tile.rs @@ -318,7 +318,9 @@ fn handle_clipboard_history() -> impl futures::Stream { { info!("Adding item to cbhist"); output - .send(Message::ClipboardHistory(content.to_owned())) + .send(Message::EditClipboardHistory(crate::app::Editable::Create( + content.to_owned(), + ))) .await .ok(); prev_byte_rep = byte_rep; diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index ff98f432..f6e21778 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -15,6 +15,7 @@ use rayon::iter::IntoParallelRefIterator; use rayon::iter::ParallelIterator; use rayon::slice::ParallelSliceMut; +use crate::app::Editable; use crate::app::SetConfigBufferFields; use crate::app::SetConfigFields; use crate::app::SetConfigThemeFields; @@ -87,6 +88,13 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { } Message::EscKeyPressed(id) => { + if !tile.query_lc.is_empty() { + return Task::batch([ + Task::done(Message::ClearSearchQuery), + Task::done(Message::ClearSearchResults), + ]); + } + match tile.page { Page::Main => {} Page::Settings => { @@ -168,8 +176,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { }; let quantity = match tile.page { - Page::Main | Page::FileSearch => 66.5, - Page::ClipboardHistory => 50., + Page::Main | Page::FileSearch | Page::ClipboardHistory => 66.5, Page::EmojiSearch => 5., Page::Settings => 0., }; @@ -435,26 +442,50 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { } } - Message::ClipboardHistory(content) => { - if !tile.clipboard_content.contains(&content) { - tile.clipboard_content.insert(0, content); - return Task::none(); - } - - let new_content_vec = tile - .clipboard_content - .par_iter() - .filter_map(|x| { - if *x == content { - None - } else { - Some(x.to_owned()) + Message::EditClipboardHistory(action) => { + match action { + Editable::Create(content) => { + if !tile.clipboard_content.contains(&content) { + tile.clipboard_content.insert(0, content); + return Task::none(); } - }) - .collect(); - tile.clipboard_content = new_content_vec; - tile.clipboard_content.insert(0, content); + let new_content_vec = tile + .clipboard_content + .par_iter() + .filter_map(|x| { + if *x == content { + None + } else { + Some(x.to_owned()) + } + }) + .collect(); + + tile.clipboard_content = new_content_vec; + tile.clipboard_content.insert(0, content); + } + Editable::Delete(content) => { + tile.clipboard_content = tile + .clipboard_content + .iter() + .filter_map(|x| { + if *x == content { + None + } else { + Some(x.to_owned()) + } + }) + .collect(); + } + Editable::Update { old, new } => { + tile.clipboard_content = tile + .clipboard_content + .iter() + .map(|x| if x == &old { new.clone() } else { x.to_owned() }) + .collect(); + } + } Task::none() } diff --git a/src/clipboard.rs b/src/clipboard.rs index 58ad024f..4b0d2257 100644 --- a/src/clipboard.rs +++ b/src/clipboard.rs @@ -19,7 +19,7 @@ impl ToApp for ClipBoardContentType { fn to_app(&self) -> App { let mut display_name = match self { ClipBoardContentType::Image(_) => "Image".to_string(), - ClipBoardContentType::Text(a) => a.to_owned(), + ClipBoardContentType::Text(a) => a.get(0..25).unwrap_or(a).to_string(), }; let self_clone = self.clone(); diff --git a/src/styles.rs b/src/styles.rs index 17c837b3..e11596d5 100644 --- a/src/styles.rs +++ b/src/styles.rs @@ -51,6 +51,20 @@ pub fn contents_style(theme: &ConfigTheme) -> container::Style { } } +pub fn delete_button_style(theme: &ConfigTheme) -> button::Style { + let red_clr = Color::from_rgb(1.0, 0.2, 0.2); + button::Style { + text_color: red_clr, + background: Some(Background::Color(theme.bg_color())), + border: Border { + color: with_alpha(red_clr, 0.3), + width: 0.5, + radius: Radius::new(15), + }, + ..Default::default() + } +} + /// Styling for each of the buttons that are what the "results" of rustcast are pub fn result_button_style(theme: &ConfigTheme) -> button::Style { button::Style {