mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-09-11 12:05:46 +00:00
feat: alert module for simple ok dialogs
This commit is contained in:
parent
504e945ba5
commit
4980876622
7 changed files with 72 additions and 85 deletions
17
src/ui/alert.rs
Normal file
17
src/ui/alert.rs
Normal 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<>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();
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -13,3 +13,4 @@ pub mod devices_box;
|
|||
pub mod preference_rows;
|
||||
pub mod macros;
|
||||
pub mod util;
|
||||
pub mod alert;
|
||||
|
|
|
@ -9,7 +9,6 @@ use crate::{
|
|||
withclones,
|
||||
};
|
||||
use adw::prelude::*;
|
||||
use gtk::prelude::*;
|
||||
use relm4::{factory::FactoryVecDeque, prelude::*};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue