diff --git a/dash-frontend/assets/gui/view/download_file.xml b/dash-frontend/assets/gui/view/download_file.xml
new file mode 100644
index 00000000..a385c4d7
--- /dev/null
+++ b/dash-frontend/assets/gui/view/download_file.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/dash-frontend/assets/lang/en.json b/dash-frontend/assets/lang/en.json
index 98212c50..9497b114 100644
--- a/dash-frontend/assets/lang/en.json
+++ b/dash-frontend/assets/lang/en.json
@@ -142,6 +142,8 @@
"CREATION_DATE": "Creation date",
"DEBUG_INFO": "Debug info",
"DISPLAY_BRIGHTNESS": "Display brightness",
+ "DOWNLOADER": "Downloader",
+ "DOWNLOADING_FILE": "Downloading file...",
"FAILED_TO_LAUNCH_APPLICATION": "Failed to launch a application:",
"GAME_LAUNCHED": "Game launched",
"GAME_LIST": {
@@ -170,6 +172,7 @@
"REMOVE": "Remove",
"SETTINGS": "Settings",
"SHOW": "Show",
+ "TARGET_PATH": "Target path",
"TERMINATE_PROCESS": "Terminate process",
"VERSION": "Version",
"WIDTH": "Width"
diff --git a/dash-frontend/src/tab/games.rs b/dash-frontend/src/tab/games.rs
index fcdc3cad..02082ef7 100644
--- a/dash-frontend/src/tab/games.rs
+++ b/dash-frontend/src/tab/games.rs
@@ -10,7 +10,7 @@ use crate::{
frontend::Frontend,
tab::{Tab, TabType},
util::steam_utils::SteamUtils,
- views::{game_list, running_games_list},
+ views::{ViewTrait, ViewUpdateParams, game_list, running_games_list},
};
pub struct TabGames {
@@ -19,7 +19,6 @@ pub struct TabGames {
view_game_list: game_list::View,
view_running_games_list: running_games_list::View,
- steam_utils: SteamUtils,
marker: PhantomData,
}
@@ -29,9 +28,11 @@ impl Tab for TabGames {
}
fn update(&mut self, frontend: &mut Frontend, time_ms: u32, _data: &mut T) -> anyhow::Result<()> {
- self
- .view_game_list
- .update(&mut frontend.layout, &mut self.steam_utils, &frontend.executor)?;
+ self.view_game_list.update(&mut ViewUpdateParams {
+ layout: &mut frontend.layout,
+ executor: &mut frontend.executor,
+ })?;
+
self.view_running_games_list.update(&mut frontend.layout, time_ms)?;
Ok(())
}
@@ -54,16 +55,17 @@ impl TabGames {
let game_list_parent = state.get_widget_id("game_list_parent")?;
let id_running_games_list_parent = state.get_widget_id("running_games_list_parent")?;
+ let mut steam_utils = SteamUtils::new()?;
+
let view_game_list = game_list::View::new(game_list::Params {
executor: frontend.executor.clone(),
frontend_tasks: frontend.tasks.clone(),
globals: globals.clone(),
layout: &mut frontend.layout,
parent_id: game_list_parent,
+ steam_utils: &steam_utils,
})?;
- let mut steam_utils = SteamUtils::new()?;
-
let view_running_games_list = running_games_list::View::new(running_games_list::Params {
globals: globals.clone(),
layout: &mut frontend.layout,
@@ -77,7 +79,6 @@ impl TabGames {
view_game_list,
view_running_games_list,
marker: PhantomData,
- steam_utils,
})
}
}
diff --git a/dash-frontend/src/tab/settings/mod.rs b/dash-frontend/src/tab/settings/mod.rs
index 19df03c2..9ab2f0f4 100644
--- a/dash-frontend/src/tab/settings/mod.rs
+++ b/dash-frontend/src/tab/settings/mod.rs
@@ -19,13 +19,12 @@ use wgui::{
},
windowing::context_menu::{self, Blueprint, ContextMenu, TickResult},
};
-use wlx_common::{
- async_executor::AsyncExecutor, config::GeneralConfig, config_io::ConfigRoot, dash_interface::RecenterMode,
-};
+use wlx_common::{config::GeneralConfig, config_io::ConfigRoot, dash_interface::RecenterMode};
use crate::{
frontend::{Frontend, FrontendTask, FrontendTasks},
tab::{Tab, TabType, settings::macros::MacroParams},
+ views::ViewUpdateParams,
};
mod macros;
@@ -86,13 +85,8 @@ struct SettingsMountParams<'a> {
parent_id: WidgetID,
}
-struct SettingsUpdateParams<'a> {
- layout: &'a mut Layout,
- executor: &'a AsyncExecutor,
-}
-
trait SettingsTab {
- fn update(&mut self, _par: SettingsUpdateParams) -> anyhow::Result<()> {
+ fn update(&mut self, _par: &mut ViewUpdateParams) -> anyhow::Result<()> {
Ok(())
}
}
@@ -117,7 +111,7 @@ impl Tab for TabSettings {
fn update(&mut self, frontend: &mut Frontend, _time_ms: u32, data: &mut T) -> anyhow::Result<()> {
if let Some(tab) = &mut self.current_tab {
- tab.update(SettingsUpdateParams {
+ tab.update(&mut ViewUpdateParams {
layout: &mut frontend.layout,
executor: &frontend.executor,
})?;
diff --git a/dash-frontend/src/tab/settings/tab_skybox.rs b/dash-frontend/src/tab/settings/tab_skybox.rs
index 5e7dda79..a490bfcc 100644
--- a/dash-frontend/src/tab/settings/tab_skybox.rs
+++ b/dash-frontend/src/tab/settings/tab_skybox.rs
@@ -3,7 +3,7 @@ use crate::{
SettingType, SettingsMountParams, SettingsTab,
macros::{options_category, options_checkbox},
},
- views::skymap_list,
+ views::{ViewTrait, ViewUpdateParams, skymap_list},
};
pub struct State {
@@ -11,8 +11,8 @@ pub struct State {
}
impl SettingsTab for State {
- fn update(&mut self, par: super::SettingsUpdateParams) -> anyhow::Result<()> {
- self.skymap_list.update(par.layout, par.executor)?;
+ fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ self.skymap_list.update(par)?;
Ok(())
}
}
diff --git a/dash-frontend/src/util/popup_manager.rs b/dash-frontend/src/util/popup_manager.rs
index 97aa7f13..75b076e5 100644
--- a/dash-frontend/src/util/popup_manager.rs
+++ b/dash-frontend/src/util/popup_manager.rs
@@ -16,7 +16,10 @@ use wgui::{
};
use wlx_common::config::GeneralConfig;
-use crate::frontend::{FrontendTask, FrontendTasks};
+use crate::{
+ frontend::{FrontendTask, FrontendTasks},
+ views::{ViewTrait, ViewUpdateParams},
+};
pub struct PopupManagerParams {
pub parent_id: WidgetID,
@@ -45,13 +48,19 @@ pub struct PopupHandle {
state: Rc>,
}
-struct PopupHolderState {
+struct PopupHolderState
+where
+ ViewType: ViewTrait,
+{
popup_handle: PopupHandle,
view: Option,
}
// we can't use #[derive(Default)] due to the fact that ViewType can't be Default.
-impl Default for PopupHolderState {
+impl Default for PopupHolderState
+where
+ ViewType: ViewTrait,
+{
fn default() -> Self {
Self {
popup_handle: Default::default(),
@@ -60,11 +69,17 @@ impl Default for PopupHolderState {
}
}
-pub struct PopupHolder {
+pub struct PopupHolder
+where
+ ViewType: ViewTrait,
+{
state: Rc>>,
}
-impl Default for PopupHolder {
+impl Default for PopupHolder
+where
+ ViewType: ViewTrait,
+{
fn default() -> Self {
Self {
state: Rc::new(RefCell::new(PopupHolderState::default())),
@@ -72,7 +87,10 @@ impl Default for PopupHolder {
}
}
-impl PopupHolderState {
+impl PopupHolderState
+where
+ ViewType: ViewTrait,
+{
fn close(&mut self) {
self.view = None;
self.popup_handle.close();
@@ -80,7 +98,10 @@ impl PopupHolderState {
}
// we can't derive(Clone) due to the fact that ViewType is non-cloneable
-impl Clone for PopupHolder {
+impl Clone for PopupHolder
+where
+ ViewType: ViewTrait,
+{
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
@@ -88,9 +109,17 @@ impl Clone for PopupHolder {
}
}
-impl PopupHolder {
- pub fn close(&self) {
- self.state.borrow_mut().close();
+impl PopupHolder
+where
+ ViewType: ViewTrait,
+{
+ pub fn update(&self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ let mut state = self.state.borrow_mut();
+ let Some(view) = &mut state.view else {
+ return Ok(());
+ };
+
+ view.update(par)
}
pub fn set_view(&self, handle: PopupHandle, view: ViewType) {
@@ -131,15 +160,20 @@ impl PopupHolder {
Ok(())
}
- pub fn get_close_callback(&self) -> Box
+ pub fn get_close_callback(&self, layout: &Layout) -> Box
where
ViewType: 'static,
{
+ let layout_tasks = layout.tasks.clone();
let weak_state = Rc::downgrade(&self.state);
Box::new(move || {
- if let Some(state) = weak_state.upgrade() {
- state.borrow_mut().close();
- }
+ // we can't borrow State here yet, dispatch it.
+ layout_tasks.push(LayoutTask::Dispatch(Box::new(move |_common| {
+ if let Some(state) = weak_state.upgrade() {
+ state.borrow_mut().close();
+ }
+ Ok(())
+ })));
})
}
}
diff --git a/dash-frontend/src/util/steam_utils.rs b/dash-frontend/src/util/steam_utils.rs
index a2c6e778..3c7faa3a 100644
--- a/dash-frontend/src/util/steam_utils.rs
+++ b/dash-frontend/src/util/steam_utils.rs
@@ -2,6 +2,7 @@ use keyvalues_parser::{Obj, Vdf};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
+#[derive(Clone)]
pub struct SteamUtils {
steam_root: PathBuf,
}
diff --git a/dash-frontend/src/views/app_launcher.rs b/dash-frontend/src/views/app_launcher.rs
index 93d4fb68..f343b201 100644
--- a/dash-frontend/src/views/app_launcher.rs
+++ b/dash-frontend/src/views/app_launcher.rs
@@ -17,6 +17,7 @@ use wlx_common::{config::GeneralConfig, dash_interface::BoxDashInterface, deskto
use crate::{
frontend::{FrontendTask, FrontendTasks, SoundType},
util::popup_manager::{MountPopupOnceParams, PopupHolder},
+ views::{ViewTrait, ViewUpdateParams},
};
#[derive(Clone, Copy, Eq, PartialEq, EnumString, VariantNames, AsRefStr)]
@@ -69,7 +70,7 @@ struct LaunchParams<'a, T> {
interface: &'a mut BoxDashInterface,
auto_start: bool,
data: &'a mut T,
- on_launched: &'a dyn Fn(),
+ on_launched: Option>,
}
pub struct View {
@@ -94,7 +95,7 @@ pub struct View {
auto_start: bool,
- on_launched: Box,
+ on_launched: Option>,
}
pub struct Params<'a> {
@@ -104,7 +105,13 @@ pub struct Params<'a> {
pub parent_id: WidgetID,
pub config: &'a GeneralConfig,
pub frontend_tasks: &'a FrontendTasks,
- pub on_launched: Box,
+ pub on_launched: Box,
+}
+
+impl ViewTrait for View {
+ fn update(&mut self, _par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ Ok(())
+ }
}
impl View {
@@ -283,7 +290,7 @@ impl View {
entry: params.entry,
frontend_tasks: params.frontend_tasks.clone(),
globals: params.globals.clone(),
- on_launched: params.on_launched,
+ on_launched: Some(params.on_launched),
})
}
@@ -319,7 +326,7 @@ impl View {
auto_start: self.auto_start,
interface,
data,
- on_launched: &self.on_launched,
+ on_launched: self.on_launched.take(),
});
}
@@ -337,7 +344,7 @@ impl View {
))));
}
- fn launch(params: LaunchParams) -> anyhow::Result<()> {
+ fn launch(mut params: LaunchParams) -> anyhow::Result<()> {
let mut env = Vec::::new();
if params.compositor_mode == CompositorMode::Native {
@@ -393,7 +400,9 @@ impl View {
params.frontend_tasks.push(FrontendTask::PlaySound(SoundType::Launch));
- (*params.on_launched)();
+ if let Some(on_launched) = params.on_launched.take() {
+ on_launched();
+ }
// we're done!
Ok(())
@@ -430,6 +439,7 @@ pub fn mount_popup(frontend_tasks: FrontendTasks, globals: WguiGlobals, entry: D
.push(FrontendTask::MountPopupOnce(MountPopupOnceParams::new(
Translation::from_raw_text(&entry.app_name),
Box::new(move |data| {
+ let on_launched = popup.get_close_callback(data.layout);
let view = View::new(Params {
entry: entry.clone(),
globals: &globals,
@@ -437,11 +447,11 @@ pub fn mount_popup(frontend_tasks: FrontendTasks, globals: WguiGlobals, entry: D
parent_id: data.id_content,
frontend_tasks: &frontend_tasks,
config: data.config,
- on_launched: popup.get_close_callback(),
+ on_launched,
})?;
popup.set_view(data.handle, view);
- Ok(popup.get_close_callback())
+ Ok(popup.get_close_callback(data.layout))
}),
)));
}
diff --git a/dash-frontend/src/views/download_file.rs b/dash-frontend/src/views/download_file.rs
new file mode 100644
index 00000000..b7eea8da
--- /dev/null
+++ b/dash-frontend/src/views/download_file.rs
@@ -0,0 +1,112 @@
+use crate::{
+ frontend::{FrontendTask, FrontendTasks},
+ util::popup_manager::{MountPopupOnceParams, PopupHolder},
+ views::{ViewTrait, ViewUpdateParams},
+};
+use std::path::PathBuf;
+use wgui::{
+ assets::AssetPath,
+ globals::WguiGlobals,
+ i18n::Translation,
+ layout::{Layout, WidgetID},
+ parser::{Fetchable, ParseDocumentParams, ParserState},
+ task::Tasks,
+ widget::label::WidgetLabel,
+};
+use wlx_common::async_executor::AsyncExecutor;
+
+pub struct Params<'a> {
+ pub globals: &'a WguiGlobals,
+ pub layout: &'a mut Layout,
+ pub executor: &'a AsyncExecutor,
+ pub parent_id: WidgetID,
+ pub target_path: PathBuf,
+ pub url: String,
+ pub on_close_request: Box,
+}
+
+#[derive(Clone)]
+enum Task {}
+
+pub struct View {
+ id_parent: WidgetID,
+ globals: WguiGlobals,
+ tasks: Tasks,
+ executor: AsyncExecutor,
+
+ #[allow(dead_code)]
+ parser_state: ParserState,
+}
+
+impl ViewTrait for View {
+ fn update(&mut self, _par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ for task in self.tasks.drain() {
+ match task {}
+ }
+ Ok(())
+ }
+}
+
+impl View {
+ pub fn new(par: Params) -> anyhow::Result {
+ let tasks = Tasks::::new();
+
+ let doc_params = ParseDocumentParams {
+ globals: par.globals.clone(),
+ path: AssetPath::BuiltIn("gui/view/download_file.xml"),
+ extra: Default::default(),
+ };
+
+ let mut parser_state = wgui::parser::parse_from_assets(&doc_params, par.layout, par.parent_id)?;
+
+ let str_target_path = par.globals.i18n().translate("TARGET_PATH");
+
+ {
+ let label_target_path = parser_state
+ .fetch_widget(&par.layout.state, "label_target_path")?
+ .widget;
+ label_target_path.cast::()?.set_text(
+ &mut par.layout.common(),
+ Translation::from_raw_text_string(format!("{}: {}", str_target_path, par.target_path.display())),
+ );
+ }
+
+ Ok(Self {
+ id_parent: par.parent_id,
+ tasks,
+ globals: par.globals.clone(),
+ executor: par.executor.clone(),
+ parser_state,
+ })
+ }
+}
+
+pub fn mount_popup(
+ frontend_tasks: FrontendTasks,
+ executor: AsyncExecutor,
+ globals: WguiGlobals,
+ popup: PopupHolder,
+ target_path: PathBuf,
+ url: String,
+) {
+ frontend_tasks
+ .clone()
+ .push(FrontendTask::MountPopupOnce(MountPopupOnceParams::new(
+ Translation::from_translation_key("DOWNLOADER"),
+ Box::new(move |data| {
+ let on_close_request = popup.get_close_callback(data.layout);
+ let view = View::new(Params {
+ globals: &globals,
+ layout: data.layout,
+ executor: &executor,
+ parent_id: data.id_content,
+ on_close_request,
+ target_path,
+ url,
+ })?;
+
+ popup.set_view(data.handle, view);
+ Ok(popup.get_close_callback(data.layout))
+ }),
+ )));
+}
diff --git a/dash-frontend/src/views/game_launcher.rs b/dash-frontend/src/views/game_launcher.rs
index d70a8239..2e889299 100644
--- a/dash-frontend/src/views/game_launcher.rs
+++ b/dash-frontend/src/views/game_launcher.rs
@@ -7,7 +7,7 @@ use crate::{
popup_manager::{MountPopupOnceParams, PopupHolder},
steam_utils::{self, AppID, AppManifest},
},
- views::game_cover,
+ views::{ViewTrait, ViewUpdateParams, game_cover},
};
use wgui::{
assets::AssetPath,
@@ -35,13 +35,14 @@ pub struct Params<'a> {
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
pub frontend_tasks: &'a FrontendTasks,
- pub on_launched: Box,
+ pub on_launched: Box,
}
+
pub struct View {
#[allow(dead_code)]
state: ParserState,
tasks: Tasks,
- on_launched: Box,
+ on_launched: Option>,
frontend_tasks: FrontendTasks,
game_cover_view_common: game_cover::ViewCommon,
@@ -49,6 +50,30 @@ pub struct View {
app_id: AppID,
}
+impl ViewTrait for View {
+ fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ loop {
+ let tasks = self.tasks.drain();
+ if tasks.is_empty() {
+ break;
+ }
+ for task in tasks {
+ match task {
+ Task::FillAppDetails(details) => self.action_fill_app_details(&mut par.layout, details)?,
+ Task::Launch => self.action_launch(),
+ Task::SetCoverArt(cover_art) => {
+ let _ = self
+ .view_cover
+ .set_cover_art(&mut self.game_cover_view_common, &mut par.layout, &cover_art);
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
impl View {
async fn fetch_details(executor: AsyncExecutor, tasks: Tasks, app_id: AppID) {
let Some(details) = cached_fetcher::get_app_details_json(executor, app_id).await else {
@@ -105,7 +130,7 @@ impl View {
Ok(Self {
state,
tasks,
- on_launched: params.on_launched,
+ on_launched: Some(params.on_launched),
frontend_tasks: params.frontend_tasks.clone(),
game_cover_view_common: game_cover::ViewCommon::new(params.globals.clone()),
view_cover,
@@ -113,28 +138,6 @@ impl View {
})
}
- pub fn update(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
- loop {
- let tasks = self.tasks.drain();
- if tasks.is_empty() {
- break;
- }
- for task in tasks {
- match task {
- Task::FillAppDetails(details) => self.action_fill_app_details(layout, details)?,
- Task::Launch => self.action_launch(),
- Task::SetCoverArt(cover_art) => {
- let _ = self
- .view_cover
- .set_cover_art(&mut self.game_cover_view_common, layout, &cover_art);
- }
- }
- }
- }
-
- Ok(())
- }
-
fn action_fill_app_details(
&mut self,
layout: &mut Layout,
@@ -189,7 +192,9 @@ impl View {
}
}
- (*self.on_launched)();
+ if let Some(on_launched) = self.on_launched.take() {
+ on_launched();
+ }
}
}
@@ -205,6 +210,7 @@ pub fn mount_popup(
.push(FrontendTask::MountPopupOnce(MountPopupOnceParams::new(
Translation::from_raw_text(&manifest.name),
Box::new(move |data| {
+ let on_launched = popup.get_close_callback(data.layout);
let view = View::new(Params {
manifest: manifest.clone(),
executor: executor.clone(),
@@ -212,11 +218,11 @@ pub fn mount_popup(
layout: data.layout,
parent_id: data.id_content,
frontend_tasks: &frontend_tasks,
- on_launched: popup.get_close_callback(),
+ on_launched,
})?;
popup.set_view(data.handle, view);
- Ok(popup.get_close_callback())
+ Ok(popup.get_close_callback(data.layout))
}),
)));
}
diff --git a/dash-frontend/src/views/game_list.rs b/dash-frontend/src/views/game_list.rs
index 89878143..ab7e6448 100644
--- a/dash-frontend/src/views/game_list.rs
+++ b/dash-frontend/src/views/game_list.rs
@@ -22,7 +22,7 @@ use crate::{
popup_manager::PopupHolder,
steam_utils::{self, AppID, SteamUtils},
},
- views::{self, game_cover},
+ views::{self, ViewTrait, ViewUpdateParams, game_cover},
};
#[derive(Clone)]
@@ -41,6 +41,7 @@ pub struct Params<'a> {
pub frontend_tasks: FrontendTasks,
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
+ pub steam_utils: &'a SteamUtils,
}
const MAX_GAMES_PER_PAGE: u32 = 30;
@@ -64,6 +65,31 @@ pub struct View {
page_count: u32,
id_label_page: WidgetID,
view_launcher: PopupHolder,
+ steam_utils: SteamUtils,
+}
+
+impl ViewTrait for View {
+ fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ loop {
+ let tasks = self.tasks.drain();
+ if tasks.is_empty() {
+ break;
+ }
+ for task in tasks {
+ match task {
+ Task::LoadManifests => self.load_manifests(),
+ Task::FillPage(page_idx) => self.fill_page(&mut par.layout, &mut par.executor, page_idx)?,
+ Task::AppManifestClicked(manifest) => self.action_app_manifest_clicked(manifest)?,
+ Task::SetCoverArt(app_id, cover_art) => self.set_cover_art(&mut par.layout, app_id, cover_art),
+ Task::PrevPage => self.page_prev(),
+ Task::NextPage => self.page_next(),
+ }
+ }
+ }
+
+ self.view_launcher.update(par)?;
+ Ok(())
+ }
}
impl View {
@@ -106,36 +132,9 @@ impl View {
page_count: 0,
id_label_page,
view_launcher: Default::default(),
+ steam_utils: params.steam_utils.clone(),
})
}
-
- pub fn update(
- &mut self,
- layout: &mut Layout,
- steam_utils: &mut SteamUtils,
- executor: &AsyncExecutor,
- ) -> anyhow::Result<()> {
- loop {
- let tasks = self.tasks.drain();
- if tasks.is_empty() {
- break;
- }
- for task in tasks {
- match task {
- Task::LoadManifests => self.load_manifests(steam_utils),
- Task::FillPage(page_idx) => self.fill_page(layout, executor, page_idx)?,
- Task::AppManifestClicked(manifest) => self.action_app_manifest_clicked(manifest)?,
- Task::SetCoverArt(app_id, cover_art) => self.set_cover_art(layout, app_id, cover_art),
- Task::PrevPage => self.page_prev(),
- Task::NextPage => self.page_next(),
- }
- }
- }
-
- self.view_launcher.with_view_res(|view| view.update(layout))?;
-
- Ok(())
- }
}
fn fill_game_list(
@@ -178,8 +177,11 @@ fn fill_game_list(
}
impl View {
- fn load_manifests(&mut self, steam_utils: &mut SteamUtils) {
- match steam_utils.list_installed_games(steam_utils::GameSortMethod::PlayDateDesc) {
+ fn load_manifests(&mut self) {
+ match self
+ .steam_utils
+ .list_installed_games(steam_utils::GameSortMethod::PlayDateDesc)
+ {
Ok(manifests) => {
self.page_count = (manifests.len() as u32 + MAX_GAMES_PER_PAGE) / MAX_GAMES_PER_PAGE;
self.all_manifests = manifests;
diff --git a/dash-frontend/src/views/mod.rs b/dash-frontend/src/views/mod.rs
index c5e89bba..e916e5bf 100644
--- a/dash-frontend/src/views/mod.rs
+++ b/dash-frontend/src/views/mod.rs
@@ -1,5 +1,8 @@
+use wlx_common::async_executor::AsyncExecutor;
+
pub mod app_launcher;
pub mod audio_settings;
+pub mod download_file;
pub mod game_cover;
pub mod game_launcher;
pub mod game_list;
@@ -8,3 +11,12 @@ pub mod remote_skymap_list;
pub mod running_games_list;
pub mod skymap_list;
pub mod skymap_list_cell;
+
+pub struct ViewUpdateParams<'a> {
+ pub layout: &'a mut wgui::layout::Layout,
+ pub executor: &'a AsyncExecutor,
+}
+
+pub trait ViewTrait {
+ fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()>;
+}
diff --git a/dash-frontend/src/views/remote_skymap_downloader.rs b/dash-frontend/src/views/remote_skymap_downloader.rs
index 66700b6b..4a2326e0 100644
--- a/dash-frontend/src/views/remote_skymap_downloader.rs
+++ b/dash-frontend/src/views/remote_skymap_downloader.rs
@@ -1,4 +1,4 @@
-use std::{collections::HashMap, rc::Rc};
+use std::{collections::HashMap, path::PathBuf, rc::Rc};
use crate::{
frontend::{FrontendTask, FrontendTasks},
@@ -6,6 +6,7 @@ use crate::{
networking::{self, skymap_catalog::SkymapResolution},
popup_manager::{MountPopupOnceParams, PopupHolder},
},
+ views::{self, ViewTrait, ViewUpdateParams},
};
use wgui::{
assets::AssetPath,
@@ -24,9 +25,10 @@ pub struct Params<'a> {
pub globals: &'a WguiGlobals,
pub layout: &'a mut Layout,
pub executor: &'a AsyncExecutor,
+ pub frontend_tasks: FrontendTasks,
pub parent_id: WidgetID,
pub entry: networking::skymap_catalog::SkymapCatalogEntry,
- pub on_close_request: Box,
+ pub on_close_request: Box,
pub preview_image: Option,
}
@@ -38,12 +40,15 @@ enum Task {
pub struct View {
id_parent: WidgetID,
entry: networking::skymap_catalog::SkymapCatalogEntry,
+ frontend_tasks: FrontendTasks,
globals: WguiGlobals,
tasks: Tasks,
executor: AsyncExecutor,
#[allow(dead_code)]
parser_state: ParserState,
+
+ popup_download: PopupHolder,
}
fn mount_resolution_button(
@@ -62,6 +67,19 @@ fn mount_resolution_button(
Ok(())
}
+impl ViewTrait for View {
+ fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ for task in self.tasks.drain() {
+ match task {
+ Task::ResolutionClicked(skymap_resolution) => {
+ self.run_download(&mut par.layout, skymap_resolution)?;
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
impl View {
pub fn new(par: Params) -> anyhow::Result {
let tasks = Tasks::::new();
@@ -150,15 +168,25 @@ impl View {
executor: par.executor.clone(),
entry: par.entry,
parser_state,
+ frontend_tasks: par.frontend_tasks,
+ popup_download: Default::default(),
})
}
- pub fn update(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
- for task in self.tasks.drain() {
- match task {
- Task::ResolutionClicked(skymap_resolution) => todo!(),
- }
- }
+ fn run_download(&mut self, layout: &mut Layout, resolution: SkymapResolution) -> anyhow::Result<()> {
+ let target_path = PathBuf::from(format!(""));
+ let Some(url) = self.entry.files.get_url_from_res(resolution) else {
+ return Ok(());
+ };
+
+ views::download_file::mount_popup(
+ self.frontend_tasks.clone(),
+ self.executor.clone(),
+ self.globals.clone(),
+ self.popup_download.clone(),
+ target_path,
+ url,
+ );
Ok(())
}
}
@@ -176,18 +204,20 @@ pub fn mount_popup(
.push(FrontendTask::MountPopupOnce(MountPopupOnceParams::new(
Translation::from_raw_text(&entry.name),
Box::new(move |data| {
+ let on_close_request = popup.get_close_callback(data.layout);
let view = View::new(Params {
globals: &globals,
layout: data.layout,
executor: &executor,
parent_id: data.id_content,
entry,
- on_close_request: popup.get_close_callback(),
+ on_close_request,
preview_image,
+ frontend_tasks: frontend_tasks.clone(),
})?;
popup.set_view(data.handle, view);
- Ok(popup.get_close_callback())
+ Ok(popup.get_close_callback(data.layout))
}),
)));
}
diff --git a/dash-frontend/src/views/remote_skymap_list.rs b/dash-frontend/src/views/remote_skymap_list.rs
index 7b7f8f59..b3ce4754 100644
--- a/dash-frontend/src/views/remote_skymap_list.rs
+++ b/dash-frontend/src/views/remote_skymap_list.rs
@@ -21,7 +21,7 @@ use crate::{
popup_manager::{MountPopupOnceParams, PopupHolder},
wgui_simple,
},
- views,
+ views::{self, ViewTrait, ViewUpdateParams},
};
pub struct Params<'a> {
@@ -29,7 +29,7 @@ pub struct Params<'a> {
pub layout: &'a mut Layout,
pub executor: &'a AsyncExecutor,
pub parent_id: WidgetID,
- pub on_close_request: Box,
+ pub on_close_request: Box,
pub frontend_tasks: FrontendTasks,
}
@@ -58,6 +58,44 @@ pub struct View {
popup_remote_skymap_downloader: PopupHolder,
}
+impl ViewTrait for View {
+ fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ self.popup_remote_skymap_downloader.update(par)?;
+
+ for task in self.tasks.drain() {
+ match task {
+ Task::SetSkymapCatalog(skymap_catalog) => {
+ par.layout.remove_widget(self.id_loading);
+ match &*skymap_catalog {
+ Ok(skymap_catalog) => {
+ self.mount_catalog(par.layout, skymap_catalog)?;
+ }
+ Err(e) => wgui_simple::create_label_error(
+ par.layout,
+ self.id_parent,
+ format!("Failed to fetch skymap catalog: {:?}", e),
+ )?,
+ }
+ }
+ Task::SetSkymapPreview((skymap_uuid, glyph_data)) => {
+ if let Some(cell) = &mut self
+ .mounted_cells
+ .iter_mut()
+ .find(|cell| cell.skymap_uuid == skymap_uuid)
+ {
+ cell.view.set_image(par.layout, glyph_data)?;
+ }
+ }
+ Task::ShowRemoteSkymapDownloader(skymap_uuid) => {
+ let preview_image = self.get_image_preview(skymap_uuid);
+ self.show_remote_skymap_downloader(skymap_uuid, preview_image)?;
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
impl View {
async fn skymap_catalog_request_wrapper(tasks: Tasks, executor: AsyncExecutor) {
let res = networking::skymap_catalog::request_catalog(&executor).await;
@@ -176,44 +214,6 @@ impl View {
}
None
}
-
- pub fn update(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
- self
- .popup_remote_skymap_downloader
- .with_view_res(|view| view.update(layout))?;
-
- for task in self.tasks.drain() {
- match task {
- Task::SetSkymapCatalog(skymap_catalog) => {
- layout.remove_widget(self.id_loading);
- match &*skymap_catalog {
- Ok(skymap_catalog) => {
- self.mount_catalog(layout, skymap_catalog)?;
- }
- Err(e) => wgui_simple::create_label_error(
- layout,
- self.id_parent,
- format!("Failed to fetch skymap catalog: {:?}", e),
- )?,
- }
- }
- Task::SetSkymapPreview((skymap_uuid, glyph_data)) => {
- if let Some(cell) = &mut self
- .mounted_cells
- .iter_mut()
- .find(|cell| cell.skymap_uuid == skymap_uuid)
- {
- cell.view.set_image(layout, glyph_data)?;
- }
- }
- Task::ShowRemoteSkymapDownloader(skymap_uuid) => {
- let preview_image = self.get_image_preview(skymap_uuid);
- self.show_remote_skymap_downloader(skymap_uuid, preview_image)?;
- }
- }
- }
- Ok(())
- }
}
pub fn mount_popup(
@@ -227,17 +227,18 @@ pub fn mount_popup(
.push(FrontendTask::MountPopupOnce(MountPopupOnceParams::new(
Translation::from_translation_key("APP_SETTINGS.DOWNLOAD_SKYMAPS"),
Box::new(move |data| {
+ let on_close_request = popup.get_close_callback(data.layout);
let view = View::new(Params {
globals: &globals,
layout: data.layout,
executor: &executor,
parent_id: data.id_content,
- on_close_request: popup.get_close_callback(),
+ on_close_request,
frontend_tasks,
})?;
popup.set_view(data.handle, view);
- Ok(popup.get_close_callback())
+ Ok(popup.get_close_callback(data.layout))
}),
)));
}
diff --git a/dash-frontend/src/views/skymap_list.rs b/dash-frontend/src/views/skymap_list.rs
index 634d21d5..466f0a5f 100644
--- a/dash-frontend/src/views/skymap_list.rs
+++ b/dash-frontend/src/views/skymap_list.rs
@@ -12,7 +12,7 @@ use wlx_common::{async_executor::AsyncExecutor, config_io};
use crate::{
frontend::FrontendTasks,
util::{popup_manager::PopupHolder, wgui_simple},
- views,
+ views::{self, ViewTrait, ViewUpdateParams},
};
#[derive(Clone)]
@@ -38,6 +38,31 @@ pub struct View {
popup_remote_skymap_list: PopupHolder,
}
+impl ViewTrait for View {
+ fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
+ self.popup_remote_skymap_list.update(par)?;
+
+ loop {
+ let tasks = self.tasks.drain();
+ if tasks.is_empty() {
+ break;
+ }
+ for task in tasks {
+ match task {
+ Task::DownloadSkymaps => {
+ self.download_skymaps(&par.executor)?;
+ }
+ Task::Refresh => {
+ self.refresh(&mut par.layout)?;
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
impl View {
pub fn new(params: Params) -> anyhow::Result {
let doc_params = &ParseDocumentParams {
@@ -72,31 +97,6 @@ impl View {
})
}
- pub fn update(&mut self, layout: &mut Layout, executor: &AsyncExecutor) -> anyhow::Result<()> {
- self
- .popup_remote_skymap_list
- .with_view_res(|view| view.update(layout))?;
-
- loop {
- let tasks = self.tasks.drain();
- if tasks.is_empty() {
- break;
- }
- for task in tasks {
- match task {
- Task::DownloadSkymaps => {
- self.download_skymaps(executor)?;
- }
- Task::Refresh => {
- self.refresh(layout)?;
- }
- }
- }
- }
-
- Ok(())
- }
-
fn download_skymaps(&mut self, executor: &AsyncExecutor) -> anyhow::Result<()> {
views::remote_skymap_list::mount_popup(
self.frontend_tasks.clone(),
diff --git a/wayvr/src/overlays/keyboard/mod.rs b/wayvr/src/overlays/keyboard/mod.rs
index dc432395..4c0401f0 100644
--- a/wayvr/src/overlays/keyboard/mod.rs
+++ b/wayvr/src/overlays/keyboard/mod.rs
@@ -461,7 +461,7 @@ fn handle_mouse_motion(
{
if !swipe_manager.is_current_swipe_empty() {
match &key.button_state {
- KeyButtonData::Key { vk, pressed } => {
+ KeyButtonData::Key { vk: _, pressed: _ } => {
if let Some(pos) = within_key_pos {
// check because mouse motion can trigger despite hover being false
if pos.x >= 0.0 && pos.x <= 1.0 && pos.y >= 0.0 && pos.y <= 1.0 {