6 Commits

8 changed files with 368 additions and 279 deletions

490
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ lto = true
gettext-rs = { version = "0.7", features = ["gettext-system"] } gettext-rs = { version = "0.7", features = ["gettext-system"] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = "0.3" tracing-subscriber = "0.3"
relm4 = { version = "0.8.1", features = ["libadwaita", "gnome_46", "macros"] } relm4 = { version = "0.9", features = ["libadwaita", "gnome_46", "macros"] }
relm4-icons = { version = "0.8.1" } relm4-icons = { version = "0.9" }
serde = { version = "1.0.199", features = ["derive"] } serde = { version = "1.0.199", features = ["derive"] }
serde_json = "1.0.116" serde_json = "1.0.116"

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="UTF-8"?>
<schemalist> <schemalist>
<schema path="/org/kuchelmeister/ToolboxTuner/" id="@app-id@" gettext-domain="@gettext-package@"> <schema path="/org/kuchelmeister/ToolboxTuner/" id="@app-id@" gettext-domain="@gettext-package@">
<key name="window-width" type="i"> <key name="window-width" type="i">
@@ -13,5 +13,10 @@
<default>false</default> <default>false</default>
<summary>Window maximized state</summary> <summary>Window maximized state</summary>
</key> </key>
<key name="terminal" type="s">
<default>""</default>
<summary>Terminal to use</summary>
</key>
</schema> </schema>
</schemalist> </schemalist>

View File

@@ -2,6 +2,7 @@ use crate::gtk::Align;
use crate::util::prerequisit::get_installed_terminals; use crate::util::prerequisit::get_installed_terminals;
use crate::util::prerequisit::is_toolbox_installed; use crate::util::prerequisit::is_toolbox_installed;
use crate::modals::settings::SettingsMsg;
use crate::util::toolbox::ToolbxContainer; use crate::util::toolbox::ToolbxContainer;
use relm4::adw::prelude::PreferencesGroupExt; use relm4::adw::prelude::PreferencesGroupExt;
use relm4::factory::FactoryHashMap; use relm4::factory::FactoryHashMap;
@@ -20,6 +21,7 @@ use crate::config::{APP_ID, PROFILE};
use crate::factories::container_list::Container; use crate::factories::container_list::Container;
use crate::factories::container_list::ContainerStatus; use crate::factories::container_list::ContainerStatus;
use crate::modals::about::AboutDialog; use crate::modals::about::AboutDialog;
use crate::modals::settings::SettingsDialog;
use crate::modals::unsupported::UnsupportedDialog; use crate::modals::unsupported::UnsupportedDialog;
use crate::modals::unsupported::UnsupportedDialogOutput; use crate::modals::unsupported::UnsupportedDialogOutput;
use crate::util::toolbox::ToolbxStatus; use crate::util::toolbox::ToolbxStatus;
@@ -29,6 +31,7 @@ use gtk::prelude::{
use gtk::{gio, glib}; use gtk::{gio, glib};
pub(super) struct App { pub(super) struct App {
settings_dialog: Controller<SettingsDialog>,
unsupported_dialog: Controller<UnsupportedDialog>, unsupported_dialog: Controller<UnsupportedDialog>,
about_dialog: Controller<AboutDialog>, about_dialog: Controller<AboutDialog>,
containers: FactoryHashMap<String, Container>, containers: FactoryHashMap<String, Container>,
@@ -48,7 +51,7 @@ pub(super) enum AppCommandMsg {
} }
relm4::new_action_group!(pub(super) WindowActionGroup, "win"); relm4::new_action_group!(pub(super) WindowActionGroup, "win");
//relm4::new_stateless_action!(PreferencesAction, WindowActionGroup, "preferences"); relm4::new_stateless_action!(PreferencesAction, WindowActionGroup, "preferences");
relm4::new_stateless_action!(pub(super) ShortcutsAction, WindowActionGroup, "show-help-overlay"); relm4::new_stateless_action!(pub(super) ShortcutsAction, WindowActionGroup, "show-help-overlay");
relm4::new_stateless_action!(AboutAction, WindowActionGroup, "about"); relm4::new_stateless_action!(AboutAction, WindowActionGroup, "about");
use crate::factories::container_list::ContainerInit; use crate::factories::container_list::ContainerInit;
@@ -64,7 +67,7 @@ impl Component for App {
menu! { menu! {
primary_menu: { primary_menu: {
section! { section! {
//"_Preferences" => PreferencesAction, "_Preferences" => PreferencesAction,
"_Keyboard" => ShortcutsAction, "_Keyboard" => ShortcutsAction,
"_About Toolbox Tuner" => AboutAction, "_About Toolbox Tuner" => AboutAction,
} }
@@ -148,6 +151,11 @@ impl Component for App {
.launch(()) .launch(())
.detach(); .detach();
let settings_dialog = SettingsDialog::builder()
.transient_for(&root)
.launch(())
.detach();
let unsupported_dialog = UnsupportedDialog::builder() let unsupported_dialog = UnsupportedDialog::builder()
.transient_for(&root) .transient_for(&root)
.launch(()) .launch(())
@@ -158,6 +166,7 @@ impl Component for App {
let containers = FactoryHashMap::builder().launch_default().detach(); let containers = FactoryHashMap::builder().launch_default().detach();
let model = Self { let model = Self {
settings_dialog,
about_dialog, about_dialog,
unsupported_dialog, unsupported_dialog,
containers, containers,
@@ -169,6 +178,13 @@ impl Component for App {
let mut actions = RelmActionGroup::<WindowActionGroup>::new(); let mut actions = RelmActionGroup::<WindowActionGroup>::new();
let preference_action = {
let settings = model.settings_dialog.sender().clone();
RelmAction::<PreferencesAction>::new_stateless(move |_| {
settings.send(SettingsMsg::OpenSettings).unwrap();
})
};
let shortcuts_action = { let shortcuts_action = {
let shortcuts = widgets.shortcuts.clone(); let shortcuts = widgets.shortcuts.clone();
RelmAction::<ShortcutsAction>::new_stateless(move |_| { RelmAction::<ShortcutsAction>::new_stateless(move |_| {
@@ -189,12 +205,12 @@ impl Component for App {
AppCommandMsg::PrerequisitsInstalled(terminals.len() > 0 && toolbox_installed) AppCommandMsg::PrerequisitsInstalled(terminals.len() > 0 && toolbox_installed)
}); });
actions.add_action(preference_action);
actions.add_action(shortcuts_action); actions.add_action(shortcuts_action);
actions.add_action(about_action); actions.add_action(about_action);
actions.register_for_widget(&widgets.main_window); actions.register_for_widget(&widgets.main_window);
widgets.load_window_size(); widgets.load_window_size();
ComponentParts { model, widgets } ComponentParts { model, widgets }
} }

View File

@@ -63,6 +63,6 @@ fn main() {
gio::ResourceLookupFlags::NONE, gio::ResourceLookupFlags::NONE,
) )
.unwrap(); .unwrap();
app.set_global_css(&glib::GString::from_utf8_checked(data.to_vec()).unwrap()); relm4::set_global_css(&glib::GString::from_utf8_checked(data.to_vec()).unwrap());
app.visible_on_activate(false).run::<App>(()); app.visible_on_activate(false).run::<App>(());
} }

View File

@@ -1,2 +1,3 @@
pub mod about; pub mod about;
pub mod settings;
pub mod unsupported; pub mod unsupported;

117
src/modals/settings.rs Normal file
View File

@@ -0,0 +1,117 @@
use crate::util::prerequisit::get_installed_terminals;
use relm4::adw::prelude::{
ComboRowExt, PreferencesGroupExt, PreferencesPageExt, PreferencesRowExt, PreferencesWindowExt,
};
use relm4::gtk::prelude::Cast;
use relm4::gtk::prelude::GtkWindowExt;
use relm4::gtk::prelude::ListModelExt;
use relm4::gtk::prelude::WidgetExt;
use relm4::view;
use relm4::{adw, gtk, ComponentParts, ComponentSender, SimpleComponent};
pub struct SettingsDialog {
hidden: bool,
terminal: String,
}
use crate::APP_ID;
use gtk::gio;
use relm4::gtk::prelude::CastNone;
use relm4::gtk::prelude::SettingsExt;
#[derive(Debug)]
pub enum SettingsMsg {
OpenSettings,
TerminalSelectionChanged(String),
}
impl SimpleComponent for SettingsDialog {
type Init = ();
type Widgets = adw::PreferencesWindow;
type Input = SettingsMsg;
type Output = ();
type Root = adw::PreferencesWindow;
fn init_root() -> Self::Root {
adw::PreferencesWindow::new()
}
fn init(
_: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = Self {
hidden: true,
terminal: "".to_string(),
};
let terminal_selection_model = gtk::gio::ListStore::new::<gtk::StringObject>();
let sort_function = |to_insert: &gtk::glib::Object,
existing: &gtk::glib::Object|
-> std::cmp::Ordering { to_insert.cmp(existing) };
let terminals = get_installed_terminals().unwrap_or_default();
terminals.iter().for_each(|t| {
terminal_selection_model.insert_sorted(
&gtk::StringObject::new(format!("{:?}", t).as_str()),
&sort_function,
);
});
let settings = gio::Settings::new(APP_ID);
let terminal = settings.string("terminal");
println!("{}", terminal);
let terminal_selection = terminal_selection_model
.find_with_equal_func(|obj| {
gtk::StringObject::new(terminal.as_str()).string()
== obj.downcast_ref::<gtk::StringObject>().unwrap().string()
})
.unwrap_or(0);
println!("{}", terminal_selection);
let str_object: String = terminal_selection_model
.item(terminal_selection)
.and_downcast::<gtk::StringObject>()
.expect("The item has to be an `StringObject`.")
.into();
sender.input(SettingsMsg::TerminalSelectionChanged(str_object));
view! {
widgets = root.clone() {
add = &adw::PreferencesPage::new() {
add = &adw::PreferencesGroup::new() {
set_title: "Terminal settings",
add = &adw::ComboRow::new() {
set_title: "Terminal",
#[wrap(Some)]
set_model = &gtk::SingleSelection::new(Some(terminal_selection_model)),
#[watch]
set_selected: terminal_selection,
connect_selected_item_notify[sender] => move |combo_row| {
let str_object: String = combo_row.selected_item().and_downcast::<gtk::StringObject>().expect("The item has to be an `StringObject`.").into();
sender.input(SettingsMsg::TerminalSelectionChanged(str_object));
},
},
},
},
}
}
ComponentParts { model, widgets }
}
fn update_view(&self, dialog: &mut Self::Widgets, _sender: ComponentSender<Self>) {
dialog.show();
}
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
match msg {
SettingsMsg::OpenSettings => {}
SettingsMsg::TerminalSelectionChanged(terminal) => {
let settings = gio::Settings::new(APP_ID);
settings.set_string("terminal", &terminal);
}
}
}
}

View File

@@ -1,8 +1,10 @@
use crate::util::toolbox::ToolbxError; use crate::util::toolbox::ToolbxError;
use std::process::Command; use std::process::Command;
#[derive(Debug)]
pub enum TerminalType { pub enum TerminalType {
GnomeTerminal, GnomeTerminal,
Konsole,
} }
pub fn get_installed_terminals() -> Result<Vec<TerminalType>, ToolbxError> { pub fn get_installed_terminals() -> Result<Vec<TerminalType>, ToolbxError> {
@@ -20,7 +22,7 @@ pub fn get_installed_terminals() -> Result<Vec<TerminalType>, ToolbxError> {
let output = output.unwrap(); let output = output.unwrap();
if output.status.code() == Some(0) { if output.status.code() == Some(0) {
Ok(vec![TerminalType::GnomeTerminal]) Ok(vec![TerminalType::GnomeTerminal, TerminalType::Konsole])
} else { } else {
Err(ToolbxError::CommandUnsuccessfulError( Err(ToolbxError::CommandUnsuccessfulError(
String::from_utf8_lossy(&output.stderr).into_owned(), String::from_utf8_lossy(&output.stderr).into_owned(),