diff --git a/src/gui/message.rs b/src/gui/message.rs index a5e6954b..f25a8ba0 100644 --- a/src/gui/message.rs +++ b/src/gui/message.rs @@ -718,6 +718,7 @@ async fn self_update_async( #[derive(Debug)] pub struct FetchModDetails { rid: RequestID, + modio_id: u32, result: Result, } @@ -744,9 +745,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: (), @@ -754,24 +759,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 a59c2bdb..0471c2c2 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -93,10 +93,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)] @@ -156,10 +156,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(), }) } @@ -441,9 +441,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(), @@ -1411,40 +1410,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() @@ -1455,7 +1449,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), { @@ -1628,7 +1623,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| { @@ -1637,8 +1641,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 {