Skip to content

Commit be27ca0

Browse files
authored
Merge pull request #234 from RustCastLabs/settings-page
Settings page
2 parents 60c698e + 86ad3bd commit be27ca0

5 files changed

Lines changed: 363 additions & 28 deletions

File tree

src/app.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::HashMap;
33

44
use crate::app::apps::{App, AppCommand, ICNS_ICON};
55
use crate::commands::Function;
6-
use crate::config::Config;
6+
use crate::config::{Config, Shelly};
77
use crate::debounce::DebouncePolicy;
88
use crate::utils::icns_data_to_handle;
99
use crate::{app::tile::ExtSender, clipboard::ClipBoardContentType};
@@ -128,7 +128,8 @@ pub enum SetConfigFields {
128128
AutoSuggest(bool),
129129
Modes(Editable<(String, String)>),
130130
Aliases(Editable<(String, String)>),
131-
SearchDirs(Editable<Vec<String>>),
131+
SearchDirs(Editable<String>),
132+
ShellCommands(Editable<Shelly>),
132133
DebounceDelay(u64),
133134
SetThemeFields(SetConfigThemeFields),
134135
SetBufferFields(SetConfigBufferFields),

src/app/pages/settings.rs

Lines changed: 295 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
use std::collections::HashMap;
44

55
use iced::widget::Slider;
6+
use iced::widget::Space;
67
use iced::widget::TextInput;
78
use iced::widget::checkbox;
89
use iced::widget::text_input;
910

1011
use crate::app::Editable;
1112
use crate::app::SetConfigBufferFields;
1213
use crate::app::SetConfigThemeFields;
14+
use crate::commands::Function;
15+
use crate::config::Shelly;
1316
use crate::styles::delete_button_style;
1417
use crate::styles::settings_add_button_style;
1518
use crate::styles::settings_checkbox_style;
@@ -204,16 +207,19 @@ pub fn settings_page(config: Config) -> Element<'static, Message> {
204207
let theme_clone = theme.clone();
205208
let font_family = settings_item_column([
206209
settings_hint_text(theme.clone(), "Set Font family"),
207-
text_input("Font family", &config.theme.font.unwrap_or("".to_string()))
208-
.on_input(move |input: String| {
209-
Message::SetConfig(SetConfigFields::SetThemeFields(SetConfigThemeFields::Font(
210-
input,
211-
)))
212-
})
213-
.on_submit(Message::WriteConfig(false))
214-
.width(Length::Fill)
215-
.style(move |_, _| settings_text_input_item_style(&theme_clone))
216-
.into(),
210+
text_input(
211+
"Font family",
212+
&config.theme.font.clone().unwrap_or("".to_string()),
213+
)
214+
.on_input(move |input: String| {
215+
Message::SetConfig(SetConfigFields::SetThemeFields(SetConfigThemeFields::Font(
216+
input,
217+
)))
218+
})
219+
.on_submit(Message::WriteConfig(false))
220+
.width(Length::Fill)
221+
.style(move |_, _| settings_text_input_item_style(&theme_clone))
222+
.into(),
217223
notice_item(theme.clone(), "What font rustcast should use"),
218224
]);
219225

@@ -372,12 +378,18 @@ pub fn settings_page(config: Config) -> Element<'static, Message> {
372378
text_clr.into(),
373379
bg_clr.into(),
374380
settings_hint_text(theme.clone(), "Aliases"),
375-
aliases_item(config.aliases, &theme),
381+
aliases_item(config.aliases.clone(), &theme),
376382
settings_hint_text(theme.clone(), "Modes"),
377-
modes_item(config.modes, &theme),
383+
modes_item(config.modes.clone(), &theme),
384+
settings_hint_text(theme.clone(), "Search Directories"),
385+
search_dirs_item(&theme, config.search_dirs.clone()),
386+
Space::new().height(30).into(),
387+
settings_hint_text(theme.clone(), "Shell commands"),
388+
shell_commands_item(config.shells.clone(), theme.clone()),
378389
Row::from_iter([
379390
savebutton(theme.clone()),
380391
default_button(theme.clone()),
392+
copy_config_button(config),
381393
wiki_button(theme.clone()),
382394
])
383395
.spacing(5)
@@ -423,18 +435,34 @@ fn default_button(theme: Theme) -> Element<'static, Message> {
423435

424436
fn wiki_button(theme: Theme) -> Element<'static, Message> {
425437
Button::new(
426-
Text::new("Open the wiki")
438+
Text::new("Open file")
427439
.align_x(Alignment::Center)
428440
.width(Length::Fill)
429441
.font(theme.font()),
430442
)
431443
.style(move |_, _| settings_save_button_style(&theme))
432444
.width(Length::Fill)
433-
.on_press(Message::RunFunction(
434-
crate::commands::Function::OpenWebsite(
435-
"https://github.com/RustCastLabs/rustcast/wiki".to_string(),
445+
.on_press(Message::RunFunction(crate::commands::Function::OpenApp(
446+
std::env::var("HOME").unwrap_or("".to_string()) + "/.config/rustcast/config.toml",
447+
)))
448+
.into()
449+
}
450+
451+
fn copy_config_button(config: Box<Config>) -> Element<'static, Message> {
452+
let theme = config.theme.clone();
453+
Button::new(
454+
Text::new("Copy config")
455+
.align_x(Alignment::Center)
456+
.width(Length::Fill)
457+
.font(theme.font()),
458+
)
459+
.style(move |_, _| settings_save_button_style(&theme))
460+
.width(Length::Fill)
461+
.on_press(Message::RunFunction(Function::CopyToClipboard(
462+
crate::clipboard::ClipBoardContentType::Text(
463+
toml::to_string(&config).unwrap_or("".to_string()),
436464
),
437-
))
465+
)))
438466
.into()
439467
}
440468

@@ -540,6 +568,47 @@ fn aliases_item(aliases: HashMap<String, String>, theme: &Theme) -> Element<'sta
540568
.into()
541569
}
542570

571+
fn search_dirs_item(theme: &Theme, search_dirs: Vec<String>) -> Element<'static, Message> {
572+
let theme_clone = theme.clone();
573+
let search_dirs = search_dirs.clone();
574+
Column::from_iter([
575+
container(
576+
Column::from_iter(search_dirs.iter().map(|dir| {
577+
let theme_clone_2 = theme.clone();
578+
let directory = dir.clone();
579+
container(
580+
Row::from_iter([
581+
dir_picker_button(directory, dir, theme_clone.clone()).into(),
582+
Button::new("Delete")
583+
.on_press(Message::SetConfig(SetConfigFields::SearchDirs(
584+
Editable::Delete(dir.clone()),
585+
)))
586+
.style(move |_, _| delete_button_style(&theme_clone_2))
587+
.into(),
588+
])
589+
.spacing(10)
590+
.align_y(Alignment::Center),
591+
)
592+
.width(Length::Fill)
593+
.align_x(Alignment::Center)
594+
.into()
595+
}))
596+
.spacing(10),
597+
)
598+
.height(Length::Fill)
599+
.width(Length::Fill)
600+
.align_x(Alignment::Center)
601+
.align_y(Alignment::Center)
602+
.into(),
603+
dir_adder_button("+", theme.to_owned()).into(),
604+
])
605+
.spacing(10)
606+
.height(Length::Fill)
607+
.width(Length::Fill)
608+
.align_x(Alignment::Center)
609+
.into()
610+
}
611+
543612
fn text_input_cell(text: String, theme: &Theme, placeholder: &str) -> TextInput<'static, Message> {
544613
text_input(placeholder, &text)
545614
.font(theme.font())
@@ -610,3 +679,212 @@ fn modes_item(modes: HashMap<String, String>, theme: &Theme) -> Element<'static,
610679
.align_x(Alignment::Center)
611680
.into()
612681
}
682+
683+
fn dir_picker_button(directory: String, dir: &str, theme: Theme) -> Button<'static, Message> {
684+
let home = std::env::var("HOME").unwrap_or("/".to_string());
685+
Button::new(Text::new(dir.to_owned().replace(&home, "~")))
686+
.on_press_with(move || {
687+
rfd::FileDialog::new()
688+
.set_directory(home.clone())
689+
.set_can_create_directories(false)
690+
.pick_folder()
691+
.map(|path| {
692+
let new = path.to_str().unwrap_or("").to_string();
693+
Message::SetConfig(SetConfigFields::SearchDirs(Editable::Update {
694+
old: directory.clone(),
695+
new,
696+
}))
697+
})
698+
.unwrap_or(Message::SetConfig(SetConfigFields::SearchDirs(
699+
Editable::Update {
700+
old: directory.clone(),
701+
new: directory.clone(),
702+
},
703+
)))
704+
})
705+
.style(move |_, _| settings_add_button_style(&theme.clone()))
706+
}
707+
708+
fn dir_adder_button(dir: &str, theme: Theme) -> Button<'static, Message> {
709+
Button::new(Text::new(dir.to_owned()))
710+
.on_press_with(move || {
711+
rfd::FileDialog::new()
712+
.set_directory(std::env::var("HOME").unwrap_or("/".to_string()))
713+
.set_can_create_directories(false)
714+
.pick_folder()
715+
.map(|path| {
716+
let new = path.to_str().unwrap_or("").to_string();
717+
Message::SetConfig(SetConfigFields::SearchDirs(Editable::Create(new)))
718+
})
719+
.unwrap_or(Message::SetConfig(SetConfigFields::SearchDirs(
720+
Editable::Create(String::new()),
721+
)))
722+
})
723+
.style(move |_, _| settings_add_button_style(&theme.clone()))
724+
}
725+
726+
fn shell_commands_item(shells: Vec<Shelly>, theme: Theme) -> Element<'static, Message> {
727+
let mut col =
728+
Column::from_iter(shells.iter().map(|x| x.editable_render(theme.clone()))).spacing(30);
729+
730+
let theme_clone = theme.clone();
731+
732+
col = col
733+
.push(
734+
Button::new(
735+
Text::new("+")
736+
.align_x(Alignment::Center)
737+
.align_y(Alignment::Center),
738+
)
739+
.style(move |_, _| settings_add_button_style(&theme_clone.clone()))
740+
.on_press(Message::SetConfig(SetConfigFields::ShellCommands(
741+
Editable::Create(Shelly::default()),
742+
))),
743+
)
744+
.width(Length::Fill)
745+
.align_x(Alignment::Center);
746+
747+
col.into()
748+
}
749+
750+
impl Shelly {
751+
pub fn editable_render(&self, theme: Theme) -> Element<'static, Message> {
752+
let shell = self.to_owned();
753+
Column::from_iter([
754+
tuple_row(
755+
shellcommand_hint_text(theme.clone(), "Display name"),
756+
text_input_cell(self.alias.clone(), &theme, "Display Name")
757+
.on_input({
758+
let shell = shell.clone();
759+
move |input| {
760+
let old = shell.clone();
761+
let mut new = old.clone();
762+
new.alias = input;
763+
Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update {
764+
old,
765+
new,
766+
}))
767+
}
768+
})
769+
.into(),
770+
)
771+
.into(),
772+
tuple_row(
773+
shellcommand_hint_text(theme.clone(), "Search name"),
774+
text_input_cell(self.alias_lc.clone(), &theme, "Search Name")
775+
.on_input({
776+
let shell = shell.clone();
777+
move |input| {
778+
let old = shell.clone();
779+
let mut new = old.clone();
780+
new.alias_lc = input;
781+
Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update {
782+
old,
783+
new,
784+
}))
785+
}
786+
})
787+
.into(),
788+
)
789+
.into(),
790+
tuple_row(
791+
shellcommand_hint_text(theme.clone(), "Command"),
792+
text_input_cell(self.command.clone(), &theme, "Command")
793+
.on_input({
794+
let shell = shell.clone();
795+
move |input| {
796+
let old = shell.clone();
797+
let mut new = old.clone();
798+
new.command = input;
799+
Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update {
800+
old,
801+
new,
802+
}))
803+
}
804+
})
805+
.into(),
806+
)
807+
.into(),
808+
tuple_row(
809+
shellcommand_hint_text(theme.clone(), "Icon File"),
810+
text_input_cell(
811+
self.icon_path.clone().unwrap_or("".to_string()),
812+
&theme,
813+
"Icon path",
814+
)
815+
.on_input({
816+
let shell = shell.clone();
817+
move |input| {
818+
let old = shell.clone();
819+
let mut new = old.clone();
820+
new.icon_path = if input.is_empty() { None } else { Some(input) };
821+
Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update {
822+
old,
823+
new,
824+
}))
825+
}
826+
})
827+
.into(),
828+
)
829+
.into(),
830+
tuple_row(
831+
shellcommand_hint_text(theme.clone(), "Hotkey"),
832+
text_input_cell(
833+
self.hotkey.clone().unwrap_or("".to_string()),
834+
&theme,
835+
"Hotkey",
836+
)
837+
.on_input({
838+
let shell = shell.clone();
839+
move |input| {
840+
let old = shell.clone();
841+
let mut new = old.clone();
842+
new.hotkey = Some(input);
843+
Message::SetConfig(SetConfigFields::ShellCommands(Editable::Update {
844+
old,
845+
new,
846+
}))
847+
}
848+
})
849+
.into(),
850+
)
851+
.into(),
852+
tuple_row(
853+
Button::new("Delete")
854+
.on_press(Message::SetConfig(SetConfigFields::ShellCommands(
855+
Editable::Delete(self.clone()),
856+
)))
857+
.style({
858+
let theme = theme.clone();
859+
move |_, _| delete_button_style(&theme)
860+
})
861+
.into(),
862+
notice_item(theme.clone(), "Icon path and hotkey are optional"),
863+
)
864+
.into(),
865+
])
866+
.spacing(10)
867+
.height(Length::Fill)
868+
.width(Length::Fill)
869+
.into()
870+
}
871+
}
872+
873+
fn tuple_row(
874+
left: Element<'static, Message>,
875+
right: Element<'static, Message>,
876+
) -> Row<'static, Message> {
877+
Row::from_iter([left, right])
878+
.spacing(10)
879+
.width(Length::Fill)
880+
}
881+
882+
fn shellcommand_hint_text(theme: Theme, text: impl ToString) -> Element<'static, Message> {
883+
let text = text.to_string();
884+
885+
Text::new(text)
886+
.font(theme.font())
887+
.color(theme.text_color(0.7))
888+
.width(WINDOW_WIDTH * 0.3)
889+
.into()
890+
}

src/app/tile/elm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
189189
.height(height as u32);
190190

191191
let text = if tile.query_lc.is_empty() {
192-
if tile.page == Page::Main {
192+
if tile.config.auto_suggest && tile.page == Page::Main {
193193
"Frequently used".to_string()
194194
} else {
195195
tile.page.to_string()

0 commit comments

Comments
 (0)