From 49808766226ec67c6242f84fab76239198298f12 Mon Sep 17 00:00:00 2001 From: Gabriele Musco Date: Tue, 1 Aug 2023 22:36:09 +0200 Subject: [PATCH] feat: alert module for simple ok dialogs --- src/ui/alert.rs | 17 +++++++++ src/ui/app.rs | 61 +++++++++++++------------------ src/ui/install_wivrn_box.rs | 18 +++------ src/ui/libsurvive_setup_window.rs | 43 +++++++++++----------- src/ui/main_view.rs | 16 ++------ src/ui/mod.rs | 1 + src/ui/profile_editor.rs | 1 - 7 files changed, 72 insertions(+), 85 deletions(-) create mode 100644 src/ui/alert.rs diff --git a/src/ui/alert.rs b/src/ui/alert.rs new file mode 100644 index 0000000..0c9288a --- /dev/null +++ b/src/ui/alert.rs @@ -0,0 +1,17 @@ +use gtk::traits::GtkWindowExt; +use relm4::{adw::traits::MessageDialogExt, prelude::*}; + +pub fn alert(title: &str, msg: Option<&str>, parent: Option<>k::Window>) { + let d = adw::MessageDialog::builder() + .modal(true) + .heading(title) + .build(); + if msg.is_some() { + d.set_body(msg.unwrap()); + } + if parent.is_some() { + d.set_transient_for(parent); + } + d.add_response("ok", "_Ok"); + d.present(); +} diff --git a/src/ui/app.rs b/src/ui/app.rs index cc272ae..34a5b6c 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -1,4 +1,5 @@ use super::about_dialog::AboutDialog; +use super::alert::alert; use super::build_window::{BuildStatus, BuildWindow}; use super::debug_view::{DebugView, DebugViewMsg}; use super::libsurvive_setup_window::LibsurviveSetupWindow; @@ -67,13 +68,9 @@ pub struct App { #[tracker::do_not_track] build_window: Controller, #[tracker::do_not_track] - dependencies_dialog: adw::MessageDialog, - #[tracker::do_not_track] setcap_confirm_dialog: adw::MessageDialog, #[tracker::do_not_track] libsurvive_setup_window: Controller, - #[tracker::do_not_track] - profile_runner_failed_dialog: adw::MessageDialog, #[tracker::do_not_track] config: Config, @@ -150,7 +147,14 @@ impl App { )); } Err(_) => { - self.profile_runner_failed_dialog.present(); + alert( + "Failed to start profile", + Some(concat!( + "You need to build the current profile before starting it.", + "\n\nYou can do this from the menu." + )), + Some(&self.app_win.clone().upcast::()), + ); } }; } @@ -217,7 +221,7 @@ impl SimpleComponent for App { connect_close_request[sender] => move |win| { sender.input(Msg::SaveWinSize(win.width(), win.height())); gtk::Inhibit(false) - } + } } } @@ -395,15 +399,18 @@ impl SimpleComponent for App { if !missing_deps.is_empty() { missing_deps.sort_unstable(); missing_deps.dedup(); // dedup only works if sorted, hence the above - self.dependencies_dialog.set_body( - missing_deps - .iter() - .map(|dep| dep.name.clone()) - .collect::>() - .join(", ") - .as_str(), + alert( + "Missing dependencies:", + Some( + missing_deps + .iter() + .map(|dep| dep.name.clone()) + .collect::>() + .join(", ") + .as_str(), + ), + Some(&self.app_win.clone().upcast::()), ); - self.dependencies_dialog.present(); return; } self.build_window @@ -497,7 +504,10 @@ impl SimpleComponent for App { self.config.save(); } Msg::Quit => { - sender.input(Msg::SaveWinSize(self.app_win.width(), self.app_win.height())); + sender.input(Msg::SaveWinSize( + self.app_win.width(), + self.app_win.height(), + )); self.application.quit(); } } @@ -511,13 +521,6 @@ impl SimpleComponent for App { let config = Config::get_config(); let win_size = config.win_size.clone(); let profiles = Self::profiles_list(&config); - let dependencies_dialog = adw::MessageDialog::builder() - .modal(true) - .transient_for(root) - .heading("Missing dependencies:") - .hide_on_close(true) - .build(); - dependencies_dialog.add_response("ok", "_Ok"); let setcap_confirm_dialog = adw::MessageDialog::builder() .modal(true) .transient_for(root) @@ -543,18 +546,6 @@ impl SimpleComponent for App { }); } - let profile_runner_failed_dialog = adw::MessageDialog::builder() - .modal(true) - .transient_for(root) - .heading("Failed to start profile") - .body(concat!( - "You need to build the current profile before starting it.", - "\n\nYou can do this from the menu." - )) - .hide_on_close(true) - .build(); - profile_runner_failed_dialog.add_response("ok", "_Ok"); - let model = App { application: init.application, app_win: root.clone(), @@ -592,9 +583,7 @@ impl SimpleComponent for App { .transient_for(root) .launch(()) .detach(), - dependencies_dialog, setcap_confirm_dialog, - profile_runner_failed_dialog, enable_debug_view: config.debug_view_enabled, config, tracker: 0, diff --git a/src/ui/install_wivrn_box.rs b/src/ui/install_wivrn_box.rs index 0b96f2d..761b736 100644 --- a/src/ui/install_wivrn_box.rs +++ b/src/ui/install_wivrn_box.rs @@ -10,12 +10,13 @@ use crate::{ use gtk::prelude::*; use relm4::{ actions::{ActionGroupName, RelmAction, RelmActionGroup}, - adw::traits::MessageDialogExt, new_action_group, new_stateless_action, prelude::*, }; use std::thread::JoinHandle; +use super::alert::alert; + #[derive(PartialEq, Eq, Debug, Clone)] pub enum InstallWivrnStatus { Success, @@ -32,7 +33,7 @@ pub struct InstallWivrnBox { #[tracker::do_not_track] install_runner: Option, #[tracker::do_not_track] - adb_missing_dialog: adw::MessageDialog, + root_win: gtk::Window, } #[derive(Debug)] @@ -188,7 +189,7 @@ impl SimpleComponent for InstallWivrnBox { } Self::Input::DownloadWivrn(link) => { if !check_dependency(adb_dep()) { - self.adb_missing_dialog.present(); + alert("ADB is not installed", Some("Please install ADB on your computer to install WiVRn on your Android headset"), Some(&self.root_win)); } else { self.set_install_wivrn_status(InstallWivrnStatus::InProgress); self.download_thread = Some(download_file(link, wivrn_apk_download_path())); @@ -210,21 +211,12 @@ impl SimpleComponent for InstallWivrnBox { root: &Self::Root, sender: ComponentSender, ) -> ComponentParts { - let adb_missing_dialog = adw::MessageDialog::builder() - .modal(true) - .transient_for(&init.root_win) - .heading("ADB is not installed") - .body("Please install ADB on your computer to install WiVRn on your Android headset") - .hide_on_close(true) - .build(); - adb_missing_dialog.add_response("ok", "_Ok"); - let model = Self { selected_profile: init.selected_profile, install_wivrn_status: InstallWivrnStatus::Done(None), download_thread: None, install_runner: None, - adb_missing_dialog, + root_win: init.root_win, tracker: 0, }; diff --git a/src/ui/libsurvive_setup_window.rs b/src/ui/libsurvive_setup_window.rs index 1b2fab1..13c00cd 100644 --- a/src/ui/libsurvive_setup_window.rs +++ b/src/ui/libsurvive_setup_window.rs @@ -1,9 +1,11 @@ use crate::{profile::Profile, runner::Runner}; -use gtk::{glib, prelude::*}; -use relm4::prelude::*; use adw::prelude::*; +use gtk::glib; +use relm4::prelude::*; use std::{cell::Cell, collections::HashMap, path::Path, rc::Rc, time::Duration}; +use super::alert::alert; + const NO_FILE_MSG: &str = "(No file selected)"; const CALIBRATION_RUN_TIME_SECONDS: f64 = 30.0; @@ -28,9 +30,6 @@ pub struct LibsurviveSetupWindow { #[tracker::do_not_track] filefilter_listmodel: gtk::gio::ListStore, - #[tracker::do_not_track] - survive_cli_not_found_dialog: adw::MessageDialog, - #[tracker::do_not_track] calibration_running: Rc>, #[tracker::do_not_track] @@ -388,7 +387,18 @@ impl SimpleComponent for LibsurviveSetupWindow { .unwrap() .scroll_to(self.loading_page.as_ref().unwrap(), true); } else { - self.survive_cli_not_found_dialog.present(); + let parent = match self.win.as_ref() { + None => None, + Some(w) => Some(w.clone().upcast::()), + }; + alert( + "Survive CLI not found", + Some(concat!( + "You might need to build this profile first, ", + "or maybe Libsurvive isn't enabled for this profile" + )), + parent.as_ref(), + ); } } } @@ -434,7 +444,11 @@ impl SimpleComponent for LibsurviveSetupWindow { let runner = self.calibration_runner.as_mut().unwrap(); runner.terminate(); let mut n_runner = self.create_calibration_runner( - self.profile.as_ref().unwrap().get_survive_cli_path().unwrap(), + self.profile + .as_ref() + .unwrap() + .get_survive_cli_path() + .unwrap(), ); n_runner.start(); self.calibration_runner = Some(n_runner); @@ -478,17 +492,6 @@ impl SimpleComponent for LibsurviveSetupWindow { let json_filter = gtk::FileFilter::new(); json_filter.add_mime_type("application/json"); - let survive_cli_not_found_dialog = adw::MessageDialog::builder() - .modal(true) - .hide_on_close(true) - .heading("Survive CLI not found") - .body(concat!( - "You might need to build this profile first, ", - "or maybe Libsurvive isn't enabled for this profile" - )) - .build(); - survive_cli_not_found_dialog.add_response("ok", "_Ok"); - let mut model = LibsurviveSetupWindow { win: None, progressbar: None, @@ -506,7 +509,6 @@ impl SimpleComponent for LibsurviveSetupWindow { calibration_running: Rc::new(Cell::new(false)), first_run_done: false, calibration_seconds_elapsed: 0.0, - survive_cli_not_found_dialog, tracker: 0, }; @@ -515,9 +517,6 @@ impl SimpleComponent for LibsurviveSetupWindow { let widgets = view_output!(); model.win = Some(widgets.win.clone()); - model - .survive_cli_not_found_dialog - .set_transient_for(Some(model.win.as_ref().unwrap())); model.progressbar = Some(widgets.progressbar.clone()); model.carousel = Some(widgets.carousel.clone()); model.loading_page = Some(widgets.loading_page.clone()); diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index aa5a239..a3e295f 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -1,10 +1,11 @@ +use super::alert::alert; use super::devices_box::{DevicesBox, DevicesBoxMsg}; use super::install_wivrn_box::{InstallWivrnBox, InstallWivrnBoxInit, InstallWivrnBoxMsg}; use super::profile_editor::{ProfileEditor, ProfileEditorMsg, ProfileEditorOutMsg}; use super::steam_launch_options_box::{SteamLaunchOptionsBox, SteamLaunchOptionsBoxMsg}; use crate::config::Config; use crate::constants::APP_NAME; -use crate::profile::{Profile, XRServiceType}; +use crate::profile::Profile; use crate::ui::app::{ AboutAction, BuildProfileAction, BuildProfileCleanAction, DebugViewToggleAction, LibsurviveSetupAction, @@ -37,8 +38,6 @@ pub struct MainView { #[tracker::do_not_track] profile_delete_confirm_dialog: adw::MessageDialog, #[tracker::do_not_track] - cannot_duplicate_profile_dialog: adw::MessageDialog, - #[tracker::do_not_track] profile_editor: Option>, #[tracker::do_not_track] root_win: gtk::Window, @@ -368,7 +367,7 @@ impl SimpleComponent for MainView { .sender() .emit(ProfileEditorMsg::Present); } else { - self.cannot_duplicate_profile_dialog.present(); + alert("This profile cannot be duplicated", None, Some(&self.root_win)); } } Self::Input::UpdateDevices(devs) => self @@ -428,14 +427,6 @@ impl SimpleComponent for MainView { }); } - let cannot_duplicate_profile_dialog = adw::MessageDialog::builder() - .modal(true) - .transient_for(&init.root_win) - .hide_on_close(true) - .heading("This profile cannot be duplicated") - .build(); - cannot_duplicate_profile_dialog.add_response("ok", "_Ok"); - let mut model = Self { xrservice_active: false, enable_debug_view: init.config.debug_view_enabled, @@ -452,7 +443,6 @@ impl SimpleComponent for MainView { selected_profile: init.selected_profile.clone(), profile_not_editable_dialog, profile_delete_confirm_dialog, - cannot_duplicate_profile_dialog, root_win: init.root_win.clone(), profile_editor: None, tracker: 0, diff --git a/src/ui/mod.rs b/src/ui/mod.rs index fb660a8..feef1da 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -13,3 +13,4 @@ pub mod devices_box; pub mod preference_rows; pub mod macros; pub mod util; +pub mod alert; diff --git a/src/ui/profile_editor.rs b/src/ui/profile_editor.rs index 2eea4aa..153049e 100644 --- a/src/ui/profile_editor.rs +++ b/src/ui/profile_editor.rs @@ -9,7 +9,6 @@ use crate::{ withclones, }; use adw::prelude::*; -use gtk::prelude::*; use relm4::{factory::FactoryVecDeque, prelude::*}; use std::{cell::RefCell, rc::Rc};