From c92611307fc934a58d4cef4fd1ee6f53caae7a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 22 Aug 2023 01:36:38 +0800 Subject: [PATCH] Allow multiple mod detail windows --- src/gui/message.rs | 27 +++++++++++----- src/gui/mod.rs | 78 ++++++++++++++++++++++++---------------------- 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/src/gui/message.rs b/src/gui/message.rs index 62bc04c1..542e270d 100644 --- a/src/gui/message.rs +++ b/src/gui/message.rs @@ -754,6 +754,7 @@ async fn self_update_async( #[derive(Debug)] pub struct FetchModDetails { rid: RequestID, + modio_id: u32, result: Result, } @@ -780,9 +781,13 @@ impl FetchModDetails { rid, handle: tokio::task::spawn(async move { let result = fetch_modio_mod_details(oauth_token, modio_id).await; - tx.send(Message::FetchModDetails(FetchModDetails { rid, result })) - .await - .unwrap(); + tx.send(Message::FetchModDetails(FetchModDetails { + rid, + result, + modio_id, + })) + .await + .unwrap(); ctx.request_repaint(); }), state: (), @@ -790,24 +795,30 @@ impl FetchModDetails { } fn receive(self, app: &mut App) { - if Some(self.rid) == app.fetch_mod_details_rid.as_ref().map(|r| r.rid) { + let mut to_remove = None; + + if let Some(req) = app.fetch_mod_details_rid.get(&self.modio_id) + && req.rid == self.rid + { match self.result { Ok(mod_details) => { info!("fetch mod details successful"); - app.mod_details = Some(mod_details); + app.mod_details.insert(mod_details.r#mod.id, mod_details); app.last_action_status = LastActionStatus::Success("fetch mod details complete".to_string()); } Err(e) => { error!("fetch mod details failed"); error!("{:#?}", e); - app.mod_details = None; - app.fetch_mod_details_rid = None; + to_remove = Some(self.modio_id); app.last_action_status = LastActionStatus::Failure("fetch mod details failed".to_string()); } } - app.integrate_rid = None; + } + + if let Some(id) = to_remove { + app.fetch_mod_details_rid.remove(&id); } } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index cbc95ff6..b2e6f9b0 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -103,10 +103,10 @@ pub struct App { needs_restart: bool, self_update_rid: Option>, original_exe_path: Option, - detailed_mod_info_window: Option, - mod_details: Option, - fetch_mod_details_rid: Option>, - mod_details_thumbnail_texture_handle: Option, + detailed_mod_info_windows: HashMap, + mod_details: HashMap, + fetch_mod_details_rid: HashMap>, + mod_details_thumbnail_texture_handle: HashMap, } #[derive(Default)] @@ -166,10 +166,10 @@ impl App { needs_restart: false, self_update_rid: None, original_exe_path: None, - detailed_mod_info_window: None, - mod_details: None, - fetch_mod_details_rid: None, - mod_details_thumbnail_texture_handle: None, + detailed_mod_info_windows: HashMap::default(), + mod_details: HashMap::default(), + fetch_mod_details_rid: HashMap::default(), + mod_details_thumbnail_texture_handle: HashMap::default(), }) } @@ -451,9 +451,8 @@ impl App { .on_hover_text_at_pointer("View details") .clicked() { - self.detailed_mod_info_window = - Some(WindowDetailedModInfo { info: info.clone() }); - self.fetch_mod_details_rid = Some(message::FetchModDetails::send( + self.detailed_mod_info_windows.insert(modio_id, WindowDetailedModInfo { info: info.clone() }); + self.fetch_mod_details_rid.insert(modio_id, message::FetchModDetails::send( &mut self.request_counter, ui.ctx(), self.tx.clone(), @@ -1429,40 +1428,35 @@ impl App { } } - fn show_detailed_mod_info(&mut self, ctx: &egui::Context) { - if let Some(WindowDetailedModInfo { info }) = &self.detailed_mod_info_window { - egui::Area::new("detailed-mod-info-overlay") - .movable(false) - .fixed_pos(Pos2::ZERO) - .order(egui::Order::Background) - .show(ctx, |ui| { - egui::Frame::none() - .fill(Color32::from_rgba_unmultiplied(0, 0, 0, 127)) - .show(ui, |ui| { - ui.allocate_space(ui.available_size()); - }) - }); + fn show_detailed_mod_info(&mut self, ctx: &egui::Context, modio_id: u32) { + let mut to_remove = Vec::new(); + if let Some(WindowDetailedModInfo { info }) = self.detailed_mod_info_windows.get(&modio_id) + { let mut open = true; egui::Window::new(&info.name) .open(&mut open) .collapsible(false) - .anchor(Align2::CENTER_TOP, Vec2::new(0.0, 30.0)) - .resizable(false) - .show(ctx, |ui| self.show_detailed_mod_info_inner(ui)); + .movable(true) + .resizable(true) + .show(ctx, |ui| self.show_detailed_mod_info_inner(ui, modio_id)); if !open { - self.detailed_mod_info_window = None; - self.mod_details = None; - self.fetch_mod_details_rid = None; - self.mod_details_thumbnail_texture_handle = None; + to_remove.push(modio_id); } } + + for id in to_remove { + self.detailed_mod_info_windows.remove(&id); + self.mod_details.remove(&id); + self.fetch_mod_details_rid.remove(&id); + self.mod_details_thumbnail_texture_handle.remove(&id); + } } - fn show_detailed_mod_info_inner(&mut self, ui: &mut egui::Ui) { - if let Some(mod_details) = &self.mod_details { + fn show_detailed_mod_info_inner(&mut self, ui: &mut egui::Ui, modio_id: u32) { + if let Some(mod_details) = &self.mod_details.get(&modio_id) { let scroll_area_height = (ui.available_height() - 60.0).clamp(0.0, f32::INFINITY); egui::ScrollArea::vertical() @@ -1473,7 +1467,8 @@ impl App { .show(ui, |ui| { let texture: &egui::TextureHandle = self .mod_details_thumbnail_texture_handle - .get_or_insert_with(|| { + .entry(modio_id) + .or_insert_with(|| { ui.ctx().load_texture( format!("{} image", mod_details.r#mod.name), { @@ -1646,7 +1641,16 @@ impl eframe::App for App { self.show_settings(ctx); self.show_lints_toggle(ctx); self.show_lint_report(ctx); - self.show_detailed_mod_info(ctx); + + let modio_ids = self + .detailed_mod_info_windows + .keys() + .copied() + .collect::>(); + + for modio_id in modio_ids { + self.show_detailed_mod_info(ctx, modio_id); + } egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { ui.with_layout(egui::Layout::right_to_left(Align::TOP), |ui| { @@ -1655,8 +1659,8 @@ impl eframe::App for App { && self.update_rid.is_none() && self.lint_rid.is_none() && self.self_update_rid.is_none() - && self.detailed_mod_info_window.is_none() - && self.fetch_mod_details_rid.is_none() + && self.detailed_mod_info_windows.is_empty() + && self.fetch_mod_details_rid.is_empty() && self.state.config.drg_pak_path.is_some(), |ui| { if let Some(args) = &self.args {