feat: alert module for simple ok dialogs

This commit is contained in:
Gabriele Musco 2023-08-01 22:36:09 +02:00
commit 4980876622
No known key found for this signature in database
GPG key ID: 1068D795C80E51DE
7 changed files with 72 additions and 85 deletions

17
src/ui/alert.rs Normal file
View file

@ -0,0 +1,17 @@
use gtk::traits::GtkWindowExt;
use relm4::{adw::traits::MessageDialogExt, prelude::*};
pub fn alert(title: &str, msg: Option<&str>, parent: Option<&gtk::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();
}

View file

@ -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<BuildWindow>,
#[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<LibsurviveSetupWindow>,
#[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::<gtk::Window>()),
);
}
};
}
@ -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::<Vec<String>>()
.join(", ")
.as_str(),
alert(
"Missing dependencies:",
Some(
missing_deps
.iter()
.map(|dep| dep.name.clone())
.collect::<Vec<String>>()
.join(", ")
.as_str(),
),
Some(&self.app_win.clone().upcast::<gtk::Window>()),
);
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,

View file

@ -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<Runner>,
#[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<Self>,
) -> ComponentParts<Self> {
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,
};

View file

@ -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<Cell<bool>>,
#[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::<gtk::Window>()),
};
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());

View file

@ -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<Controller<ProfileEditor>>,
#[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,

View file

@ -13,3 +13,4 @@ pub mod devices_box;
pub mod preference_rows;
pub mod macros;
pub mod util;
pub mod alert;

View file

@ -9,7 +9,6 @@ use crate::{
withclones,
};
use adw::prelude::*;
use gtk::prelude::*;
use relm4::{factory::FactoryVecDeque, prelude::*};
use std::{cell::RefCell, rc::Rc};