diff --git a/alvr/dashboard/src/dashboard/basic_components/modal.rs b/alvr/dashboard/src/dashboard/basic_components/modal.rs deleted file mode 100644 index 697129b753..0000000000 --- a/alvr/dashboard/src/dashboard/basic_components/modal.rs +++ /dev/null @@ -1,52 +0,0 @@ -use eframe::egui::{Align, Align2, Layout, Ui, Window}; - -pub enum ModalResponse { - Ok, - Cancel, -} - -pub fn modal( - ui: &mut Ui, - title: &str, - content: impl FnOnce(&mut Ui, f32), // arg 2: available width - do_not_show_again: Option<&mut bool>, - visible: &mut bool, -) -> Option { - let mut response = None; - if *visible { - Window::new(title) - .collapsible(false) - .resizable(false) - .default_width(200_f32) - .anchor(Align2::CENTER_CENTER, (0_f32, 0_f32)) - .show(ui.ctx(), |ui| { - ui.vertical_centered_justified(|ui| { - ui.add_space(10_f32); - content(ui, ui.available_width() - 8_f32); // extra offset to avoid window resizing. todo: find origin - ui.add_space(10_f32); - - if let Some(do_not_show_again) = do_not_show_again { - ui.checkbox(do_not_show_again, "Do not ask again"); - } - - ui.columns(2, |cols| { - for (i, col) in cols.iter_mut().enumerate() { - col.with_layout(Layout::top_down_justified(Align::Center), |ui| { - if i == 0 { - if ui.button("Cancel").clicked() { - *visible = false; - response = Some(ModalResponse::Cancel); - } - } else if ui.button("OK").clicked() { - *visible = false; - response = Some(ModalResponse::Ok); - } - }); - } - }); - }); - }); - } - - response -} diff --git a/alvr/dashboard/src/dashboard/components/settings.rs b/alvr/dashboard/src/dashboard/components/settings.rs index 509fd57b6e..108d475bbe 100644 --- a/alvr/dashboard/src/dashboard/components/settings.rs +++ b/alvr/dashboard/src/dashboard/components/settings.rs @@ -2,8 +2,8 @@ use super::{ presets::{builtin_schema, PresetControl}, NestingInfo, SettingControl, }; -use crate::dashboard::{DisplayString, ServerRequest}; -use alvr_gui_common::theme; +use crate::dashboard::ServerRequest; +use alvr_gui_common::{theme, DisplayString}; use alvr_packets::AudioDevicesList; use alvr_session::{SessionSettings, Settings}; use eframe::egui::{self, Align, Frame, Grid, Layout, RichText, ScrollArea, Ui}; diff --git a/alvr/dashboard/src/dashboard/components/settings_controls/boolean.rs b/alvr/dashboard/src/dashboard/components/settings_controls/boolean.rs index f7c871b5a2..30fdf7e393 100644 --- a/alvr/dashboard/src/dashboard/components/settings_controls/boolean.rs +++ b/alvr/dashboard/src/dashboard/components/settings_controls/boolean.rs @@ -1,5 +1,4 @@ use super::{reset, NestingInfo}; -use crate::dashboard::basic_components; use alvr_packets::PathValuePair; use eframe::{ egui::{Layout, Ui}, @@ -46,7 +45,7 @@ impl Control { } ui.with_layout(Layout::left_to_right(Align::Center), |ui| { - if basic_components::switch(ui, enabled_mut).clicked() { + if alvr_gui_common::switch(ui, enabled_mut).clicked() { request = get_request(&self.nesting_info, *enabled_mut); } diff --git a/alvr/dashboard/src/dashboard/components/settings_controls/choice.rs b/alvr/dashboard/src/dashboard/components/settings_controls/choice.rs index 3523043e64..4380d0f060 100644 --- a/alvr/dashboard/src/dashboard/components/settings_controls/choice.rs +++ b/alvr/dashboard/src/dashboard/components/settings_controls/choice.rs @@ -1,5 +1,5 @@ use super::{reset, NestingInfo, SettingControl}; -use crate::dashboard::{basic_components, get_id, DisplayString}; +use alvr_gui_common::DisplayString; use alvr_packets::PathValuePair; use alvr_session::settings_schema::{ChoiceControlType, SchemaEntry, SchemaNode}; use eframe::{ @@ -94,7 +94,7 @@ impl Control { variant_indices, variant_controls, gui: gui.unwrap_or(ChoiceControlType::Dropdown), - combobox_id: get_id(), + combobox_id: alvr_gui_common::get_id(), } } @@ -122,7 +122,7 @@ impl Control { let mut request = None; ui.with_layout(Layout::left_to_right(Align::Center), |ui| { if matches!(&self.gui, ChoiceControlType::ButtonGroup) { - if basic_components::button_group_clicked(ui, &self.variant_labels, variant_mut) { + if alvr_gui_common::button_group_clicked(ui, &self.variant_labels, variant_mut) { request = get_request(&self.nesting_info, variant_mut); } } else if let Some(mut index) = self.variant_indices.get(variant_mut).cloned() { diff --git a/alvr/dashboard/src/dashboard/components/settings_controls/presets/higher_order_choice.rs b/alvr/dashboard/src/dashboard/components/settings_controls/presets/higher_order_choice.rs index e5669b1025..29defb198c 100644 --- a/alvr/dashboard/src/dashboard/components/settings_controls/presets/higher_order_choice.rs +++ b/alvr/dashboard/src/dashboard/components/settings_controls/presets/higher_order_choice.rs @@ -1,10 +1,7 @@ use std::collections::{HashMap, HashSet}; use super::schema::{HigherOrderChoiceSchema, PresetModifierOperation}; -use crate::dashboard::{ - basic_components, - components::{self, NestingInfo, SettingControl, INDENTATION_STEP}, -}; +use crate::dashboard::components::{self, NestingInfo, SettingControl, INDENTATION_STEP}; use alvr_gui_common::theme::{ log_colors::{INFO_LIGHT, WARNING_LIGHT}, OK_GREEN, @@ -145,11 +142,11 @@ impl Control { if let Some(string) = &self.help { if ui.colored_label(INFO_LIGHT, "❓").hovered() { - basic_components::tooltip(ui, &format!("{}_help_tooltip", self.name), string); + alvr_gui_common::tooltip(ui, &format!("{}_help_tooltip", self.name), string); } } if self.steamvr_restart_flag && ui.colored_label(WARNING_LIGHT, "⚠").hovered() { - basic_components::tooltip( + alvr_gui_common::tooltip( ui, "steamvr_restart_tooltip", &format!( @@ -161,7 +158,7 @@ impl Control { // The emoji is blue but it will be green in the UI if self.real_time_flag && ui.colored_label(OK_GREEN, "🔵").hovered() { - basic_components::tooltip( + alvr_gui_common::tooltip( ui, "real_time_tooltip", "This setting can be changed in real-time during streaming!", diff --git a/alvr/dashboard/src/dashboard/components/settings_controls/section.rs b/alvr/dashboard/src/dashboard/components/settings_controls/section.rs index 9d83b3171c..0c502ad93b 100644 --- a/alvr/dashboard/src/dashboard/components/settings_controls/section.rs +++ b/alvr/dashboard/src/dashboard/components/settings_controls/section.rs @@ -1,8 +1,10 @@ use super::{collapsible, NestingInfo, SettingControl, INDENTATION_STEP}; -use crate::dashboard::{basic_components, DisplayString}; -use alvr_gui_common::theme::{ - log_colors::{INFO_LIGHT, WARNING_LIGHT}, - OK_GREEN, +use alvr_gui_common::{ + theme::{ + log_colors::{INFO_LIGHT, WARNING_LIGHT}, + OK_GREEN, + }, + DisplayString, }; use alvr_packets::PathValuePair; use alvr_session::settings_schema::{SchemaEntry, SchemaNode}; @@ -114,7 +116,7 @@ impl Control { if let Some(string) = &entry.help { if ui.colored_label(INFO_LIGHT, "❓").hovered() { - basic_components::tooltip( + alvr_gui_common::tooltip( ui, &format!("{}_help_tooltip", entry.id.display), string, @@ -123,7 +125,7 @@ impl Control { } if entry.steamvr_restart_flag && ui.colored_label(WARNING_LIGHT, "⚠").hovered() { - basic_components::tooltip( + alvr_gui_common::tooltip( ui, "steamvr_restart_tooltip", &format!( @@ -135,7 +137,7 @@ impl Control { // The emoji is blue but it will be green in the UI if entry.real_time_flag && ui.colored_label(OK_GREEN, "🔵").hovered() { - basic_components::tooltip( + alvr_gui_common::tooltip( ui, "real_time_tooltip", "This setting can be changed in real-time during streaming!", diff --git a/alvr/dashboard/src/dashboard/components/settings_controls/switch.rs b/alvr/dashboard/src/dashboard/components/settings_controls/switch.rs index 240f4c82ee..a07c22a332 100644 --- a/alvr/dashboard/src/dashboard/components/settings_controls/switch.rs +++ b/alvr/dashboard/src/dashboard/components/settings_controls/switch.rs @@ -1,5 +1,4 @@ use super::{reset, NestingInfo, SettingControl}; -use crate::dashboard::basic_components; use alvr_packets::PathValuePair; use alvr_session::settings_schema::SchemaNode; use eframe::{ @@ -63,7 +62,7 @@ impl Control { } ui.with_layout(Layout::left_to_right(Align::Center), |ui| { - if basic_components::switch(ui, enabled_mut).clicked() { + if alvr_gui_common::switch(ui, enabled_mut).clicked() { request = get_request(&self.nesting_info, *enabled_mut); } diff --git a/alvr/dashboard/src/dashboard/mod.rs b/alvr/dashboard/src/dashboard/mod.rs index 4fdca6f1dc..0ca3b675f0 100644 --- a/alvr/dashboard/src/dashboard/mod.rs +++ b/alvr/dashboard/src/dashboard/mod.rs @@ -1,4 +1,3 @@ -mod basic_components; mod components; use self::components::{ @@ -11,37 +10,7 @@ use alvr_gui_common::theme; use alvr_packets::{PathValuePair, ServerRequest}; use alvr_session::SessionConfig; use eframe::egui::{self, Align, CentralPanel, Frame, Layout, Margin, RichText, SidePanel, Stroke}; -use std::{ - collections::BTreeMap, - ops::Deref, - sync::{atomic::AtomicUsize, Arc}, -}; - -#[derive(Clone)] -pub struct DisplayString { - pub id: String, - pub display: String, -} - -impl From<(String, String)> for DisplayString { - fn from((id, display): (String, String)) -> Self { - Self { id, display } - } -} - -impl Deref for DisplayString { - type Target = String; - - fn deref(&self) -> &String { - &self.id - } -} - -fn get_id() -> usize { - static NEXT_ID: AtomicUsize = AtomicUsize::new(0); - - NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed) -} +use std::{collections::BTreeMap, sync::Arc}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] enum Tab { diff --git a/alvr/dashboard/src/dashboard/basic_components/button_group.rs b/alvr/gui_common/src/basic_components/button_group.rs similarity index 88% rename from alvr/dashboard/src/dashboard/basic_components/button_group.rs rename to alvr/gui_common/src/basic_components/button_group.rs index 3a003c8c9e..309b3f6e25 100644 --- a/alvr/dashboard/src/dashboard/basic_components/button_group.rs +++ b/alvr/gui_common/src/basic_components/button_group.rs @@ -1,5 +1,5 @@ -use crate::dashboard::DisplayString; -use eframe::egui::Ui; +use crate::DisplayString; +use egui::Ui; // todo: use a custom widget pub fn button_group_clicked( diff --git a/alvr/dashboard/src/dashboard/basic_components/mod.rs b/alvr/gui_common/src/basic_components/mod.rs similarity index 78% rename from alvr/dashboard/src/dashboard/basic_components/mod.rs rename to alvr/gui_common/src/basic_components/mod.rs index 2df2792ce7..c88a5603ef 100644 --- a/alvr/dashboard/src/dashboard/basic_components/mod.rs +++ b/alvr/gui_common/src/basic_components/mod.rs @@ -1,7 +1,9 @@ mod button_group; +mod modal; mod switch; mod tooltip; pub use button_group::*; +pub use modal::*; pub use switch::*; pub use tooltip::*; diff --git a/alvr/gui_common/src/basic_components/modal.rs b/alvr/gui_common/src/basic_components/modal.rs new file mode 100644 index 0000000000..9b122952b5 --- /dev/null +++ b/alvr/gui_common/src/basic_components/modal.rs @@ -0,0 +1,56 @@ +use egui::{Align, Align2, Context, Layout, Ui, Window}; +use std::fmt::{self, Display, Formatter}; + +#[derive(Clone, PartialEq)] +pub enum ModalButton { + Ok, + Cancel, + Close, + Custom(String), +} + +impl Display for ModalButton { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + ModalButton::Ok => write!(f, "OK"), + ModalButton::Cancel => write!(f, "Cancel"), + ModalButton::Close => write!(f, "Close"), + ModalButton::Custom(text) => write!(f, "{}", text), + } + } +} + +pub fn modal( + context: &Context, + title: &str, + content: Option, + buttons: &[ModalButton], +) -> Option { + let mut response = None; + + Window::new(title) + .anchor(Align2::CENTER_CENTER, (0.0, 0.0)) + .collapsible(false) + .resizable(false) + .show(context, |ui| { + ui.vertical_centered_justified(|ui| { + if let Some(content) = content { + ui.add_space(10.0); + content(ui); + ui.add_space(10.0); + } + + ui.columns(buttons.len(), |cols| { + for (idx, response_type) in buttons.iter().enumerate() { + cols[idx].with_layout(Layout::top_down_justified(Align::Center), |ui| { + if ui.button(response_type.to_string()).clicked() { + response = Some(response_type.clone()); + } + }); + } + }); + }); + }); + + response +} diff --git a/alvr/dashboard/src/dashboard/basic_components/switch.rs b/alvr/gui_common/src/basic_components/switch.rs similarity index 92% rename from alvr/dashboard/src/dashboard/basic_components/switch.rs rename to alvr/gui_common/src/basic_components/switch.rs index 1c636fa0a0..2953296001 100644 --- a/alvr/dashboard/src/dashboard/basic_components/switch.rs +++ b/alvr/gui_common/src/basic_components/switch.rs @@ -1,4 +1,4 @@ -use eframe::egui::{self, Response, Sense, Ui, WidgetInfo, WidgetType}; +use egui::{self, Response, Sense, Ui, WidgetInfo, WidgetType}; pub fn switch(ui: &mut Ui, on: &mut bool) -> Response { let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0, 1.0); diff --git a/alvr/dashboard/src/dashboard/basic_components/tooltip.rs b/alvr/gui_common/src/basic_components/tooltip.rs similarity index 78% rename from alvr/dashboard/src/dashboard/basic_components/tooltip.rs rename to alvr/gui_common/src/basic_components/tooltip.rs index 8b27a0ba00..d1913649cc 100644 --- a/alvr/dashboard/src/dashboard/basic_components/tooltip.rs +++ b/alvr/gui_common/src/basic_components/tooltip.rs @@ -1,4 +1,4 @@ -use eframe::egui::{self, popup, Ui}; +use egui::{self, popup, Ui}; pub fn tooltip(ui: &mut Ui, id: &str, text: &str) { popup::show_tooltip_text(ui.ctx(), ui.layer_id(), egui::Id::new(id), text); diff --git a/alvr/gui_common/src/lib.rs b/alvr/gui_common/src/lib.rs index 9757ba5fc1..313a2cd8d3 100644 --- a/alvr/gui_common/src/lib.rs +++ b/alvr/gui_common/src/lib.rs @@ -1 +1,32 @@ +mod basic_components; pub mod theme; + +pub use basic_components::*; + +use std::{ops::Deref, sync::atomic::AtomicUsize}; + +pub fn get_id() -> usize { + static NEXT_ID: AtomicUsize = AtomicUsize::new(0); + + NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed) +} + +#[derive(Clone)] +pub struct DisplayString { + pub id: String, + pub display: String, +} + +impl From<(String, String)> for DisplayString { + fn from((id, display): (String, String)) -> Self { + Self { id, display } + } +} + +impl Deref for DisplayString { + type Target = String; + + fn deref(&self) -> &String { + &self.id + } +} diff --git a/alvr/launcher/src/ui.rs b/alvr/launcher/src/ui.rs index 5cb401670a..46420b4879 100644 --- a/alvr/launcher/src/ui.rs +++ b/alvr/launcher/src/ui.rs @@ -1,10 +1,11 @@ use crate::{actions, InstallationInfo, Progress, ReleaseChannelsInfo, UiMessage, WorkerMessage}; +use alvr_gui_common::ModalButton; use eframe::{ egui::{ self, Button, CentralPanel, ComboBox, Context, Frame, Grid, Layout, ProgressBar, RichText, - ViewportCommand, Window, + Ui, ViewportCommand, }, - emath::{Align, Align2}, + emath::Align, epaint::Color32, }; use std::{ @@ -19,12 +20,12 @@ enum State { } #[derive(Default)] -enum Popup { +enum PopupType { #[default] None, DeleteInstallation(String), EditVersion(String), - Version(VersionPopup), + Version(Version), } #[derive(Clone, PartialEq, Eq)] @@ -35,21 +36,17 @@ enum ReleaseChannelType { #[derive(Clone, PartialEq, Eq)] struct Version { - version: String, + string: String, release_channel: ReleaseChannelType, } -struct VersionPopup { - version: Version, -} - pub struct Launcher { worker_message_receiver: Receiver, ui_message_sender: Sender, state: State, release_channels_info: Option, installations: Vec, - popup: Popup, + popup: PopupType, } impl Launcher { @@ -66,190 +63,177 @@ impl Launcher { state: State::Default, release_channels_info: None, installations: actions::get_installations(), - popup: Popup::None, + popup: PopupType::None, } } - fn version_popup(&mut self, ctx: &Context, mut version_popup: VersionPopup) -> Popup { - Window::new("Add version") - .anchor(Align2::CENTER_CENTER, (0.0, 0.0)) - .resizable(false) - .collapsible(false) - .show(ctx, |ui| { + fn version_popup(&mut self, ctx: &Context, version: Version) -> PopupType { + let response = alvr_gui_common::modal( + ctx, + "Add version", + { // Safety: unwrap is safe because the "Add release" button is available after populating the release_channels_info. let release_channels_info = self.release_channels_info.as_ref().unwrap(); - let (channel, version_str, versions): (&str, String, Vec) = - match version_popup.version.release_channel.clone() { - ReleaseChannelType::Stable => ( - "Stable", - version_popup.version.version.clone(), - release_channels_info - .stable - .iter() - .map(|release| Version { - version: release.version.clone(), - release_channel: ReleaseChannelType::Stable, - }) - .collect(), - ), - ReleaseChannelType::Nightly => ( - "Nightly", - version_popup.version.version.clone(), - release_channels_info - .nightly - .iter() - .map(|release| Version { - version: release.version.clone(), - release_channel: ReleaseChannelType::Nightly, - }) - .collect(), - ), - }; - Grid::new("add-version-grid").num_columns(2).show(ui, |ui| { - ui.label("Channel"); - - ui.with_layout(Layout::right_to_left(Align::Min), |ui| { - ComboBox::from_id_source("channel") - .selected_text(channel) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut version_popup.version, - Version { - version: self - .release_channels_info - .as_ref() - .unwrap() - .stable[0] - .version - .clone(), + let mut version = version.clone(); + Some(move |ui: &mut Ui| { + let (channel, version_str, versions): (&str, String, Vec) = + match version.release_channel.clone() { + ReleaseChannelType::Stable => ( + "Stable", + version.string.clone(), + release_channels_info + .stable + .iter() + .map(|release| Version { + string: release.version.clone(), release_channel: ReleaseChannelType::Stable, - }, - "Stable", - ); - ui.selectable_value( - &mut version_popup.version, - Version { - version: self - .release_channels_info - .as_ref() - .unwrap() - .nightly[0] - .version - .clone(), + }) + .collect(), + ), + ReleaseChannelType::Nightly => ( + "Nightly", + version.string.clone(), + release_channels_info + .nightly + .iter() + .map(|release| Version { + string: release.version.clone(), release_channel: ReleaseChannelType::Nightly, - }, - "Nightly", - ); - }) - }); - ui.end_row(); + }) + .collect(), + ), + }; + Grid::new("add-version-grid").num_columns(2).show(ui, |ui| { + ui.label("Channel"); - ui.label("Version"); - ui.with_layout(Layout::right_to_left(Align::Min), |ui| { - ComboBox::from_id_source("version") - .selected_text(version_str) - .show_ui(ui, |ui| { - for version in versions { + ui.with_layout(Layout::right_to_left(Align::Min), |ui| { + ComboBox::from_id_source("channel") + .selected_text(channel) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut version, + Version { + string: release_channels_info.stable[0].version.clone(), + release_channel: ReleaseChannelType::Stable, + }, + "Stable", + ); ui.selectable_value( - &mut version_popup.version, - version.clone(), - version.version, + &mut version, + Version { + string: release_channels_info.nightly[0] + .version + .clone(), + release_channel: ReleaseChannelType::Nightly, + }, + "Nightly", ); - } - }) + }) + }); + ui.end_row(); + + ui.label("Version"); + ui.with_layout(Layout::right_to_left(Align::Min), |ui| { + ComboBox::from_id_source("version") + .selected_text(version_str) + .show_ui(ui, |ui| { + for ver in versions { + ui.selectable_value(&mut version, ver.clone(), ver.string); + } + }) + }); + ui.end_row(); }); - ui.end_row(); - }); - ui.columns(2, |ui| { - if ui[0].button("Cancel").clicked() { - return Popup::None; - } + }) + }, + &[ModalButton::Cancel, ModalButton::Custom("Install".into())], + ); - if ui[1].button("Install").clicked() { - self.ui_message_sender - .send(UiMessage::InstallServer( - match &version_popup.version.release_channel { - ReleaseChannelType::Stable => release_channels_info - .stable - .iter() - .find(|release| { - release.version == version_popup.version.version - }) - .unwrap() - .clone(), - ReleaseChannelType::Nightly => release_channels_info - .nightly - .iter() - .find(|release| { - release.version == version_popup.version.version - }) - .unwrap() - .clone(), - }, - )) - .unwrap(); - return Popup::None; - } + match response { + Some(ModalButton::Cancel) => PopupType::None, + Some(ModalButton::Custom(_)) => { + self.ui_message_sender + .send(UiMessage::InstallServer(match &version.release_channel { + ReleaseChannelType::Stable => self + .release_channels_info + .as_ref() + .unwrap() + .stable + .iter() + .find(|release| release.version == version.string) + .unwrap() + .clone(), + ReleaseChannelType::Nightly => self + .release_channels_info + .as_ref() + .unwrap() + .nightly + .iter() + .find(|release| release.version == version.string) + .unwrap() + .clone(), + })) + .ok(); - Popup::Version(version_popup) - }) - }) - .unwrap() - .inner - .unwrap() + PopupType::None + } + _ => PopupType::Version(version), + } } - fn edit_popup(&self, ctx: &Context, version: String) -> Popup { - Window::new("Edit version") - .anchor(Align2::CENTER_CENTER, (0.0, 0.0)) - .resizable(false) - .collapsible(false) - .show(ctx, |ui| { + fn edit_popup(&self, ctx: &Context, version: String) -> PopupType { + let mut delete_version = false; + let response = alvr_gui_common::modal( + ctx, + "Edit version", + Some(|ui: &mut Ui| { ui.with_layout(Layout::top_down_justified(Align::Center), |ui| { - if ui.button("Delete version").clicked() { - return Popup::DeleteInstallation(version); - }; - if ui.button("Close").clicked() { - return Popup::None; - } + delete_version = ui.button("Delete version").clicked(); + }); + }), + &[ModalButton::Close], + ); - Popup::EditVersion(version) - }) - .inner - }) - .unwrap() - .inner - .unwrap() + if delete_version { + PopupType::DeleteInstallation(version) + } else if matches!(response, Some(ModalButton::Close)) { + PopupType::None + } else { + PopupType::EditVersion(version) + } } - fn delete_popup(&mut self, ctx: &Context, version: String) -> Popup { - Window::new("Are you sure?") - .anchor(Align2::CENTER_CENTER, (0.0, 0.0)) - .resizable(false) - .collapsible(false) - .show(ctx, |ui| { - ui.with_layout(Layout::top_down(Align::Center), |ui| { - ui.label(format!("This will permanently delete version {}", version)); - }); - ui.columns(2, |ui| { - if ui[0].button("Cancel").clicked() { - return Popup::None; - } - if ui[1].button("Delete version").clicked() { - if let Err(e) = actions::delete_installation(&version) { - self.state = State::Error(format!("Failed to delete version: {e}")); - } + fn delete_popup(&mut self, ctx: &Context, version: String) -> PopupType { + let response = alvr_gui_common::modal( + ctx, + "Are you sure?", + Some({ + let version = version.clone(); + move |ui: &mut Ui| { + ui.with_layout(Layout::top_down(Align::Center), |ui| { + ui.label(format!("This will permanently delete version {}", version)); + }); + } + }), + &[ + ModalButton::Cancel, + ModalButton::Custom("Delete version".into()), + ], + ); + + match response { + Some(ModalButton::Cancel) => PopupType::None, + Some(ModalButton::Custom(_)) => { + if let Err(e) = actions::delete_installation(&version) { + self.state = State::Error(format!("Failed to delete version: {e}")); + } - self.installations = actions::get_installations(); + self.installations = actions::get_installations(); - return Popup::None; - } - Popup::DeleteInstallation(version) - }) - }) - .unwrap() - .inner - .unwrap() + PopupType::None + } + _ => PopupType::DeleteInstallation(version), + } } } @@ -292,7 +276,7 @@ impl eframe::App for Launcher { ui.label(&installation.version); ui.with_layout(Layout::right_to_left(Align::Min), |ui| { if ui.button("Edit").clicked() { - self.popup = Popup::EditVersion( + self.popup = PopupType::EditVersion( installation.version.clone(), ); } @@ -323,7 +307,7 @@ impl eframe::App for Launcher { .send(UiMessage::InstallClient( release_info, )) - .unwrap(); + .ok(); } else { self.state = State::Error( "Failed to get release info".into(), @@ -338,7 +322,7 @@ impl eframe::App for Launcher { Ok(()) => { self.ui_message_sender .send(UiMessage::Quit) - .unwrap(); + .ok(); ctx.send_viewport_cmd( ViewportCommand::Close, ); @@ -360,21 +344,19 @@ impl eframe::App for Launcher { ) .clicked() { - self.popup = Popup::Version(VersionPopup { - version: Version { - version: self.release_channels_info.as_ref().unwrap().stable[0] - .version - .clone(), - release_channel: ReleaseChannelType::Stable, - }, + self.popup = PopupType::Version(Version { + string: self.release_channels_info.as_ref().unwrap().stable[0] + .version + .clone(), + release_channel: ReleaseChannelType::Stable, }); } let popup = match mem::take(&mut self.popup) { - Popup::Version(version_popup) => self.version_popup(ctx, version_popup), - Popup::EditVersion(version) => self.edit_popup(ctx, version), - Popup::DeleteInstallation(version) => self.delete_popup(ctx, version), - Popup::None => Popup::None, + PopupType::Version(version) => self.version_popup(ctx, version), + PopupType::EditVersion(version) => self.edit_popup(ctx, version), + PopupType::DeleteInstallation(version) => self.delete_popup(ctx, version), + PopupType::None => PopupType::None, }; self.popup = popup; }); @@ -399,7 +381,7 @@ impl eframe::App for Launcher { }); if ctx.input(|i| i.viewport().close_requested()) { - self.ui_message_sender.send(UiMessage::Quit).unwrap(); + self.ui_message_sender.send(UiMessage::Quit).ok(); } } }