From 9d2e3d9d3b6f5010989c0b55bf313bbb3d6235a7 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 10:13:37 +0800 Subject: [PATCH 01/12] add copy config and open config file button --- src/app/pages/settings.rs | 55 +++++++++++++++++++++++++++------------ src/app/tile/update.rs | 5 ++++ 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/app/pages/settings.rs b/src/app/pages/settings.rs index 5186d54..250599b 100644 --- a/src/app/pages/settings.rs +++ b/src/app/pages/settings.rs @@ -10,6 +10,7 @@ use iced::widget::text_input; use crate::app::Editable; use crate::app::SetConfigBufferFields; use crate::app::SetConfigThemeFields; +use crate::commands::Function; use crate::styles::delete_button_style; use crate::styles::settings_add_button_style; use crate::styles::settings_checkbox_style; @@ -204,16 +205,19 @@ pub fn settings_page(config: Config) -> Element<'static, Message> { let theme_clone = theme.clone(); let font_family = settings_item_column([ settings_hint_text(theme.clone(), "Set Font family"), - text_input("Font family", &config.theme.font.unwrap_or("".to_string())) - .on_input(move |input: String| { - Message::SetConfig(SetConfigFields::SetThemeFields(SetConfigThemeFields::Font( - input, - ))) - }) - .on_submit(Message::WriteConfig(false)) - .width(Length::Fill) - .style(move |_, _| settings_text_input_item_style(&theme_clone)) - .into(), + text_input( + "Font family", + &config.theme.font.clone().unwrap_or("".to_string()), + ) + .on_input(move |input: String| { + Message::SetConfig(SetConfigFields::SetThemeFields(SetConfigThemeFields::Font( + input, + ))) + }) + .on_submit(Message::WriteConfig(false)) + .width(Length::Fill) + .style(move |_, _| settings_text_input_item_style(&theme_clone)) + .into(), notice_item(theme.clone(), "What font rustcast should use"), ]); @@ -372,12 +376,13 @@ pub fn settings_page(config: Config) -> Element<'static, Message> { text_clr.into(), bg_clr.into(), settings_hint_text(theme.clone(), "Aliases"), - aliases_item(config.aliases, &theme), + aliases_item(config.aliases.clone(), &theme), settings_hint_text(theme.clone(), "Modes"), - modes_item(config.modes, &theme), + modes_item(config.modes.clone(), &theme), Row::from_iter([ savebutton(theme.clone()), default_button(theme.clone()), + copy_config_button(config), wiki_button(theme.clone()), ]) .spacing(5) @@ -423,18 +428,34 @@ fn default_button(theme: Theme) -> Element<'static, Message> { fn wiki_button(theme: Theme) -> Element<'static, Message> { Button::new( - Text::new("Open the wiki") + Text::new("Open file") + .align_x(Alignment::Center) + .width(Length::Fill) + .font(theme.font()), + ) + .style(move |_, _| settings_save_button_style(&theme)) + .width(Length::Fill) + .on_press(Message::RunFunction(crate::commands::Function::OpenApp( + std::env::var("HOME").unwrap_or("".to_string()) + "/.config/rustcast/config.toml", + ))) + .into() +} + +fn copy_config_button(config: Box) -> Element<'static, Message> { + let theme = config.theme.clone(); + Button::new( + Text::new("Copy config") .align_x(Alignment::Center) .width(Length::Fill) .font(theme.font()), ) .style(move |_, _| settings_save_button_style(&theme)) .width(Length::Fill) - .on_press(Message::RunFunction( - crate::commands::Function::OpenWebsite( - "https://github.com/RustCastLabs/rustcast/wiki".to_string(), + .on_press(Message::RunFunction(Function::CopyToClipboard( + crate::clipboard::ClipBoardContentType::Text( + toml::to_string(&config).unwrap_or("".to_string()), ), - )) + ))) .into() } diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index c1ccdff..6f6b194 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -363,6 +363,10 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { Message::RunFunction(command) => { command.execute(&tile.config); + let page_task = match tile.page { + Page::Settings => Task::done(Message::SwitchToPage(Page::Main)), + _ => Task::none(), + }; let return_focus_task = match &command { Function::OpenApp(_) | Function::GoogleSearch(_) => Task::none(), @@ -376,6 +380,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { window::latest() .map(|x| x.unwrap()) .map(Message::HideWindow) + .chain(page_task) .chain(Task::done(Message::ClearSearchQuery)) .chain(return_focus_task) } From 6a0c68467ad0efc330975942bb5b67a1eb686c00 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 12:47:04 +0800 Subject: [PATCH 02/12] add search directories to settings page --- src/app.rs | 2 +- src/app/pages/settings.rs | 90 +++++++++++++++++++++++++++++++++++++++ src/app/tile/elm.rs | 2 +- src/app/tile/update.rs | 18 +++++--- 4 files changed, 105 insertions(+), 7 deletions(-) diff --git a/src/app.rs b/src/app.rs index 16c7cab..d306dfb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -128,7 +128,7 @@ pub enum SetConfigFields { AutoSuggest(bool), Modes(Editable<(String, String)>), Aliases(Editable<(String, String)>), - SearchDirs(Editable>), + SearchDirs(Editable), DebounceDelay(u64), SetThemeFields(SetConfigThemeFields), SetBufferFields(SetConfigBufferFields), diff --git a/src/app/pages/settings.rs b/src/app/pages/settings.rs index 250599b..b6f4ef0 100644 --- a/src/app/pages/settings.rs +++ b/src/app/pages/settings.rs @@ -379,6 +379,8 @@ pub fn settings_page(config: Config) -> Element<'static, Message> { aliases_item(config.aliases.clone(), &theme), settings_hint_text(theme.clone(), "Modes"), modes_item(config.modes.clone(), &theme), + settings_hint_text(theme.clone(), "Search Directories"), + search_dirs_item(&theme, config.search_dirs.clone()), Row::from_iter([ savebutton(theme.clone()), default_button(theme.clone()), @@ -561,6 +563,47 @@ fn aliases_item(aliases: HashMap, theme: &Theme) -> Element<'sta .into() } +fn search_dirs_item(theme: &Theme, search_dirs: Vec) -> Element<'static, Message> { + let theme_clone = theme.clone(); + let search_dirs = search_dirs.clone(); + Column::from_iter([ + container( + Column::from_iter(search_dirs.iter().map(|dir| { + let theme_clone_2 = theme.clone(); + let directory = dir.clone(); + container( + Row::from_iter([ + dir_picker_button(directory, dir, theme_clone.clone()).into(), + Button::new("Delete") + .on_press(Message::SetConfig(SetConfigFields::SearchDirs( + Editable::Delete(dir.clone()), + ))) + .style(move |_, _| delete_button_style(&theme_clone_2)) + .into(), + ]) + .spacing(10) + .align_y(Alignment::Center), + ) + .width(Length::Fill) + .align_x(Alignment::Center) + .into() + })) + .spacing(10), + ) + .height(Length::Fill) + .width(Length::Fill) + .align_x(Alignment::Center) + .align_y(Alignment::Center) + .into(), + dir_adder_button("+", theme.to_owned()).into(), + ]) + .spacing(10) + .height(Length::Fill) + .width(Length::Fill) + .align_x(Alignment::Center) + .into() +} + fn text_input_cell(text: String, theme: &Theme, placeholder: &str) -> TextInput<'static, Message> { text_input(placeholder, &text) .font(theme.font()) @@ -631,3 +674,50 @@ fn modes_item(modes: HashMap, theme: &Theme) -> Element<'static, .align_x(Alignment::Center) .into() } + +fn dir_picker_button(directory: String, dir: &str, theme: Theme) -> Button<'static, Message> { + let home = std::env::var("HOME").unwrap_or("/".to_string()); + Button::new(Text::new(dir.to_owned().replace(&home, "~"))) + .on_press_with(move || { + let msg = rfd::FileDialog::new() + .set_directory(home.clone()) + .set_can_create_directories(false) + .pick_folder() + .map(|path| { + let new = path.to_str().unwrap_or("").to_string(); + Message::SetConfig(SetConfigFields::SearchDirs(Editable::Update { + old: directory.clone(), + new, + })) + }) + .unwrap_or(Message::SetConfig(SetConfigFields::SearchDirs( + Editable::Update { + old: directory.clone(), + new: directory.clone(), + }, + ))); + + msg + }) + .style(move |_, _| settings_add_button_style(&theme.clone())) +} + +fn dir_adder_button(dir: &str, theme: Theme) -> Button<'static, Message> { + Button::new(Text::new(dir.to_owned())) + .on_press_with(move || { + let msg = rfd::FileDialog::new() + .set_directory(std::env::var("HOME").unwrap_or("/".to_string())) + .set_can_create_directories(false) + .pick_folder() + .map(|path| { + let new = path.to_str().unwrap_or("").to_string(); + Message::SetConfig(SetConfigFields::SearchDirs(Editable::Create(new))) + }) + .unwrap_or(Message::SetConfig(SetConfigFields::SearchDirs( + Editable::Create(String::new()), + ))); + + msg + }) + .style(move |_, _| settings_add_button_style(&theme.clone())) +} diff --git a/src/app/tile/elm.rs b/src/app/tile/elm.rs index a64bea8..6c87da9 100644 --- a/src/app/tile/elm.rs +++ b/src/app/tile/elm.rs @@ -179,7 +179,7 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> { .height(height as u32); let text = if tile.query_lc.is_empty() { - if tile.page == Page::Main { + if tile.config.auto_suggest && tile.page == Page::Main { "Frequently used".to_string() } else { tile.page.to_string() diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index 6f6b194..aaa1c76 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -600,14 +600,14 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { final_config.aliases.insert(new.0, new.1); } SetConfigFields::SearchDirs(Editable::Create(dir)) => { - final_config.search_dirs = dir + final_config.search_dirs.push(dir); } SetConfigFields::SearchDirs(Editable::Delete(dirs)) => { final_config.search_dirs = final_config .search_dirs .iter() .filter_map(|dir| { - if !dirs.contains(dir) { + if &dirs != dir { Some(dir.to_owned()) } else { None @@ -616,8 +616,17 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { .collect(); } SetConfigFields::SearchDirs(Editable::Update { old, new }) => { - let _ = old; - let _ = new; + final_config.search_dirs = final_config + .search_dirs + .iter() + .map(|dir| { + if dir == &old { + new.clone() + } else { + dir.to_owned() + } + }) + .collect(); } SetConfigFields::SearchUrl(url) => final_config.search_url = url, SetConfigFields::PlaceHolder(placeholder) => final_config.placeholder = placeholder, @@ -651,7 +660,6 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { SetConfigFields::ToDefault => { final_config = Config::default(); final_config.shells = tile.config.shells.clone(); - final_config.search_dirs = tile.config.search_dirs.clone(); } }; From aa663344ed6c4a30bb2dd5d0f9cbb7e263f17913 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 12:47:25 +0800 Subject: [PATCH 03/12] clippy --- src/app/pages/settings.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/pages/settings.rs b/src/app/pages/settings.rs index b6f4ef0..91a0099 100644 --- a/src/app/pages/settings.rs +++ b/src/app/pages/settings.rs @@ -679,7 +679,9 @@ fn dir_picker_button(directory: String, dir: &str, theme: Theme) -> Button<'stat let home = std::env::var("HOME").unwrap_or("/".to_string()); Button::new(Text::new(dir.to_owned().replace(&home, "~"))) .on_press_with(move || { - let msg = rfd::FileDialog::new() + + + rfd::FileDialog::new() .set_directory(home.clone()) .set_can_create_directories(false) .pick_folder() @@ -695,9 +697,7 @@ fn dir_picker_button(directory: String, dir: &str, theme: Theme) -> Button<'stat old: directory.clone(), new: directory.clone(), }, - ))); - - msg + ))) }) .style(move |_, _| settings_add_button_style(&theme.clone())) } @@ -705,7 +705,9 @@ fn dir_picker_button(directory: String, dir: &str, theme: Theme) -> Button<'stat fn dir_adder_button(dir: &str, theme: Theme) -> Button<'static, Message> { Button::new(Text::new(dir.to_owned())) .on_press_with(move || { - let msg = rfd::FileDialog::new() + + + rfd::FileDialog::new() .set_directory(std::env::var("HOME").unwrap_or("/".to_string())) .set_can_create_directories(false) .pick_folder() @@ -715,9 +717,7 @@ fn dir_adder_button(dir: &str, theme: Theme) -> Button<'static, Message> { }) .unwrap_or(Message::SetConfig(SetConfigFields::SearchDirs( Editable::Create(String::new()), - ))); - - msg + ))) }) .style(move |_, _| settings_add_button_style(&theme.clone())) } From 7cb8041f89c0d227fbea224253403db1670c4a92 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 12:50:15 +0800 Subject: [PATCH 04/12] format -_- --- src/app/pages/settings.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app/pages/settings.rs b/src/app/pages/settings.rs index 91a0099..16e06e7 100644 --- a/src/app/pages/settings.rs +++ b/src/app/pages/settings.rs @@ -679,8 +679,6 @@ fn dir_picker_button(directory: String, dir: &str, theme: Theme) -> Button<'stat let home = std::env::var("HOME").unwrap_or("/".to_string()); Button::new(Text::new(dir.to_owned().replace(&home, "~"))) .on_press_with(move || { - - rfd::FileDialog::new() .set_directory(home.clone()) .set_can_create_directories(false) @@ -705,8 +703,6 @@ fn dir_picker_button(directory: String, dir: &str, theme: Theme) -> Button<'stat fn dir_adder_button(dir: &str, theme: Theme) -> Button<'static, Message> { Button::new(Text::new(dir.to_owned())) .on_press_with(move || { - - rfd::FileDialog::new() .set_directory(std::env::var("HOME").unwrap_or("/".to_string())) .set_can_create_directories(false) From 4336882a33d179aa19f2c831bb224922bdcb46dd Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 14:01:57 +0800 Subject: [PATCH 05/12] only add search directories if they don't exist --- src/app/tile/update.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index aaa1c76..408773f 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -600,7 +600,9 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { final_config.aliases.insert(new.0, new.1); } SetConfigFields::SearchDirs(Editable::Create(dir)) => { - final_config.search_dirs.push(dir); + if !final_config.search_dirs.contains(&dir) { + final_config.search_dirs.push(dir); + } } SetConfigFields::SearchDirs(Editable::Delete(dirs)) => { final_config.search_dirs = final_config From 7116c2c2ce4faea68ba48e6e9eab50389a8cb730 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 16:07:57 +0800 Subject: [PATCH 06/12] Add shell commands UI --- abcd.txt | 1 + src/app.rs | 3 +- src/app/pages/settings.rs | 149 ++++++++++++++++++++++++++++++++++++++ src/app/tile/update.rs | 44 ++++++++++- src/config.rs | 10 +-- 5 files changed, 200 insertions(+), 7 deletions(-) create mode 100644 abcd.txt diff --git a/abcd.txt b/abcd.txt new file mode 100644 index 0000000..deba01f --- /dev/null +++ b/abcd.txt @@ -0,0 +1 @@ +something diff --git a/src/app.rs b/src/app.rs index d306dfb..49ce678 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use crate::app::apps::{App, AppCommand, ICNS_ICON}; use crate::commands::Function; -use crate::config::Config; +use crate::config::{Config, Shelly}; use crate::debounce::DebouncePolicy; use crate::utils::icns_data_to_handle; use crate::{app::tile::ExtSender, clipboard::ClipBoardContentType}; @@ -129,6 +129,7 @@ pub enum SetConfigFields { Modes(Editable<(String, String)>), Aliases(Editable<(String, String)>), SearchDirs(Editable), + ShellCommands(Editable), DebounceDelay(u64), SetThemeFields(SetConfigThemeFields), SetBufferFields(SetConfigBufferFields), diff --git a/src/app/pages/settings.rs b/src/app/pages/settings.rs index 16e06e7..a674ac3 100644 --- a/src/app/pages/settings.rs +++ b/src/app/pages/settings.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use iced::widget::Slider; +use iced::widget::Space; use iced::widget::TextInput; use iced::widget::checkbox; use iced::widget::text_input; @@ -11,6 +12,7 @@ use crate::app::Editable; use crate::app::SetConfigBufferFields; use crate::app::SetConfigThemeFields; use crate::commands::Function; +use crate::config::Shelly; use crate::styles::delete_button_style; use crate::styles::settings_add_button_style; use crate::styles::settings_checkbox_style; @@ -381,6 +383,9 @@ pub fn settings_page(config: Config) -> Element<'static, Message> { modes_item(config.modes.clone(), &theme), settings_hint_text(theme.clone(), "Search Directories"), search_dirs_item(&theme, config.search_dirs.clone()), + Space::new().height(30).into(), + settings_hint_text(theme.clone(), "Shell commands"), + shell_commands_item(config.shells.clone(), theme.clone()), Row::from_iter([ savebutton(theme.clone()), default_button(theme.clone()), @@ -717,3 +722,147 @@ fn dir_adder_button(dir: &str, theme: Theme) -> Button<'static, Message> { }) .style(move |_, _| settings_add_button_style(&theme.clone())) } + +fn shell_commands_item(shells: Vec, theme: Theme) -> Element<'static, Message> { + let mut col = + Column::from_iter(shells.iter().map(|x| x.editable_render(theme.clone()))).spacing(30); + + let theme_clone = theme.clone(); + + col = col + .push( + Button::new( + Text::new("+") + .align_x(Alignment::Center) + .align_y(Alignment::Center), + ) + .style(move |_, _| settings_add_button_style(&theme_clone.clone())) + .on_press(Message::SetConfig(SetConfigFields::ShellCommands( + Editable::Create(Shelly::default()), + ))), + ) + .width(Length::Fill) + .align_x(Alignment::Center); + + col.into() +} + +impl Shelly { + pub fn editable_render(&self, theme: Theme) -> Element<'static, Message> { + let shell = self.to_owned(); + Column::from_iter([ + tuple_row( + shellcommand_hint_text(theme.clone(), "Display name"), + text_input_cell(self.alias.clone(), &theme, "Display Name") + .on_input({ + let shell = shell.clone(); + move |input| { + let old = shell.clone(); + let mut new = old.clone(); + new.alias = input; + Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update { + old, + new, + })) + } + }) + .into(), + ) + .into(), + tuple_row( + shellcommand_hint_text(theme.clone(), "Search name"), + text_input_cell(self.alias_lc.clone(), &theme, "Search Name") + .on_input({ + let shell = shell.clone(); + move |input| { + let old = shell.clone(); + let mut new = old.clone(); + new.alias_lc = input; + Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update { + old, + new, + })) + } + }) + .into(), + ) + .into(), + tuple_row( + shellcommand_hint_text(theme.clone(), "Command"), + text_input_cell(self.command.clone(), &theme, "Command") + .on_input({ + let shell = shell.clone(); + move |input| { + let old = shell.clone(); + let mut new = old.clone(); + new.command = input; + Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update { + old, + new, + })) + } + }) + .into(), + ) + .into(), + tuple_row( + shellcommand_hint_text(theme.clone(), "Icon File"), + text_input_cell( + self.icon_path.clone().unwrap_or("".to_string()), + &theme, + "Icon path", + ) + .on_input({ + let shell = shell.clone(); + move |input| { + let old = shell.clone(); + let mut new = old.clone(); + new.icon_path = if input.is_empty() { None } else { Some(input) }; + Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update { + old, + new, + })) + } + }) + .into(), + ) + .into(), + tuple_row( + Button::new("Delete") + .on_press(Message::SetConfig(SetConfigFields::ShellCommands( + Editable::Delete(self.clone()), + ))) + .style({ + let theme = theme.clone(); + move |_, _| delete_button_style(&theme) + }) + .into(), + notice_item(theme.clone(), "Icon path is optional"), + ) + .into(), + ]) + .spacing(10) + .height(Length::Fill) + .width(Length::Fill) + .into() + } +} + +fn tuple_row( + left: Element<'static, Message>, + right: Element<'static, Message>, +) -> Row<'static, Message> { + Row::from_iter([left, right]) + .spacing(10) + .width(Length::Fill) +} + +fn shellcommand_hint_text(theme: Theme, text: impl ToString) -> Element<'static, Message> { + let text = text.to_string(); + + Text::new(text) + .font(theme.font()) + .color(theme.text_color(0.7)) + .width(WINDOW_WIDTH * 0.3) + .into() +} diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index 408773f..e404ebe 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -261,6 +261,13 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { Err(_) => return Task::none(), }; + let update_apps_task = if tile.config.shells != new_config.shells { + info!("App Update required"); + Task::done(Message::UpdateApps) + } else { + Task::none() + }; + if let Some(icon) = tile.tray_icon.as_mut() { icon.set_visible(new_config.clone().show_trayicon) .unwrap_or(()); @@ -280,7 +287,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { tile.theme = new_config.theme.to_owned().into(); tile.config = new_config; - Task::done(Message::LoadRanking) + Task::batch([Task::done(Message::LoadRanking), update_apps_task]) } Message::KeyPressed(hk_id) => { @@ -630,6 +637,41 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { }) .collect(); } + + SetConfigFields::ShellCommands(Editable::Create(shell_command)) => { + if !final_config.shells.contains(&shell_command) { + final_config.shells.push(shell_command); + } + } + + SetConfigFields::ShellCommands(Editable::Delete(shell_command)) => { + final_config.shells = final_config + .shells + .iter() + .filter_map(|shell| { + if &shell_command != shell { + Some(shell.to_owned()) + } else { + None + } + }) + .collect(); + } + + SetConfigFields::ShellCommands(Editable::Update { old, new }) => { + final_config.shells = final_config + .shells + .iter() + .map(|shell| { + if shell == &old { + new.clone() + } else { + shell.to_owned() + } + }) + .collect(); + } + SetConfigFields::SearchUrl(url) => final_config.search_url = url, SetConfigFields::PlaceHolder(placeholder) => final_config.placeholder = placeholder, SetConfigFields::AutoSuggest(status) => final_config.auto_suggest = status, diff --git a/src/config.rs b/src/config.rs index 7126f0c..fc6eb2b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -178,12 +178,12 @@ impl Default for Buffer { /// Command is the command it will run when the button is clicked /// Icon_path is the path to an icon, but this is optional /// Alias is the text that is used to call this command / search for it -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)] pub struct Shelly { - command: String, - icon_path: Option, - alias: String, - alias_lc: String, + pub command: String, + pub icon_path: Option, + pub alias: String, + pub alias_lc: String, } impl ToApp for Shelly { From e7e9e9aa336aaa5c29e6989cb793a6f4de04f635 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 16:15:41 +0800 Subject: [PATCH 07/12] Don't not reset shell commands on default button --- src/app/tile.rs | 4 +++- src/app/tile/update.rs | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/tile.rs b/src/app/tile.rs index ef5b62b..bef0927 100644 --- a/src/app/tile.rs +++ b/src/app/tile.rs @@ -69,7 +69,9 @@ impl AppIndex { None => return, }; - app.ranking += 1; + if app.ranking != -1 { + app.ranking += 1; + } } fn set_ranking(&mut self, name: &str, rank: i32) { diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index e404ebe..1658277 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -703,7 +703,6 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { } SetConfigFields::ToDefault => { final_config = Config::default(); - final_config.shells = tile.config.shells.clone(); } }; From c3030d13bad5b96c4bb15093106afde474955e57 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 16:16:52 +0800 Subject: [PATCH 08/12] Revert "Don't not reset shell commands on default button" This reverts commit e7e9e9aa336aaa5c29e6989cb793a6f4de04f635. --- src/app/tile.rs | 4 +--- src/app/tile/update.rs | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/tile.rs b/src/app/tile.rs index bef0927..ef5b62b 100644 --- a/src/app/tile.rs +++ b/src/app/tile.rs @@ -69,9 +69,7 @@ impl AppIndex { None => return, }; - if app.ranking != -1 { - app.ranking += 1; - } + app.ranking += 1; } fn set_ranking(&mut self, name: &str, rank: i32) { diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index 1658277..e404ebe 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -703,6 +703,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { } SetConfigFields::ToDefault => { final_config = Config::default(); + final_config.shells = tile.config.shells.clone(); } }; From 36504fed77d6ca2fc571e08f1d87b4f752ba03a9 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 16:17:16 +0800 Subject: [PATCH 09/12] reset shell commands on default button --- src/app/tile/update.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/tile/update.rs b/src/app/tile/update.rs index e404ebe..1658277 100644 --- a/src/app/tile/update.rs +++ b/src/app/tile/update.rs @@ -703,7 +703,6 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task { } SetConfigFields::ToDefault => { final_config = Config::default(); - final_config.shells = tile.config.shells.clone(); } }; From c3785a235c81a18cdc42d23e140ef08d72f8353d Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 17:54:49 +0800 Subject: [PATCH 10/12] remove abcd.txt --- abcd.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 abcd.txt diff --git a/abcd.txt b/abcd.txt deleted file mode 100644 index deba01f..0000000 --- a/abcd.txt +++ /dev/null @@ -1 +0,0 @@ -something From a020ec2a6bdc39df75c233705f56ff8b7a9c8ffb Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 18:49:27 +0800 Subject: [PATCH 11/12] add hotkey item to settings page --- src/app/pages/settings.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/app/pages/settings.rs b/src/app/pages/settings.rs index a674ac3..e7bfcbf 100644 --- a/src/app/pages/settings.rs +++ b/src/app/pages/settings.rs @@ -827,6 +827,24 @@ impl Shelly { .into(), ) .into(), + tuple_row( + shellcommand_hint_text(theme.clone(), "Hotkey"), + text_input_cell(self.hotkey.clone().unwrap_or("".to_string()), &theme, "Hotkey") + .on_input({ + let shell = shell.clone(); + move |input| { + let old = shell.clone(); + let mut new = old.clone(); + new.hotkey = Some(input); + Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update { + old, + new, + })) + } + }) + .into(), + ) + .into(), tuple_row( Button::new("Delete") .on_press(Message::SetConfig(SetConfigFields::ShellCommands( @@ -837,7 +855,7 @@ impl Shelly { move |_, _| delete_button_style(&theme) }) .into(), - notice_item(theme.clone(), "Icon path is optional"), + notice_item(theme.clone(), "Icon path and hotkey are optional"), ) .into(), ]) From 86ad3bde6b4134f2b9b52aa50d28001faf5d1983 Mon Sep 17 00:00:00 2001 From: unsecretised Date: Fri, 27 Mar 2026 18:49:35 +0800 Subject: [PATCH 12/12] format -_- --- src/app/pages/settings.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/app/pages/settings.rs b/src/app/pages/settings.rs index e7bfcbf..a2dd755 100644 --- a/src/app/pages/settings.rs +++ b/src/app/pages/settings.rs @@ -829,20 +829,24 @@ impl Shelly { .into(), tuple_row( shellcommand_hint_text(theme.clone(), "Hotkey"), - text_input_cell(self.hotkey.clone().unwrap_or("".to_string()), &theme, "Hotkey") - .on_input({ - let shell = shell.clone(); - move |input| { - let old = shell.clone(); - let mut new = old.clone(); - new.hotkey = Some(input); - Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update { - old, - new, - })) - } - }) - .into(), + text_input_cell( + self.hotkey.clone().unwrap_or("".to_string()), + &theme, + "Hotkey", + ) + .on_input({ + let shell = shell.clone(); + move |input| { + let old = shell.clone(); + let mut new = old.clone(); + new.hotkey = Some(input); + Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update { + old, + new, + })) + } + }) + .into(), ) .into(), tuple_row(