dash-frontend: skymap preview fetch (done), reformat Cargo.toml files

This commit is contained in:
Aleksander 2026-04-06 16:59:09 +02:00 committed by galister
parent f2dcdcc6c3
commit 68daa5b3df
21 changed files with 198 additions and 87 deletions

1
Cargo.lock generated
View File

@ -1548,6 +1548,7 @@ dependencies = [
"smol",
"smol-hyper",
"strum",
"uuid",
"wayvr-ipc",
"wgui",
"wlx-common",

View File

@ -1,3 +1,42 @@
[workspace]
resolver = "3"
members = [
"dash-frontend",
"scripts/prost_build",
"uidev",
"wayvr",
"wayvr-ipc",
"wayvrctl",
"wgui",
"wlx-capture",
"wlx-common",
]
[workspace.dependencies]
anyhow = "1.0.100"
clap = { version = "4.5.53", features = ["derive"] }
glam = { version = "0.30.9", features = ["mint", "serde"] }
idmap = "0.2.2"
idmap-derive = "0.2.22"
log = "0.4.29"
regex = "1.12.2"
rust-embed = "8.9.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.145"
slotmap = "1.1.1"
smol = "2.0.2"
strum = { version = "0.27.2", features = ["derive"] }
uuid = { version = "1.19.0", features = ["fast-rng", "v4", "serde"] }
vulkano = { version = "0.35.2", default-features = false, features = [
"macros",
] }
vulkano-shaders = "0.35.0"
wayland-client = { version = "0.31.11" }
xdg = "3.0.0"
[patch.crates-io]
vulkano = { git = "https://github.com/galister/vulkano.git", rev = "cf7f92867928a56ce16b376037c1120f2b167678" }
[profile.dev]
opt-level = 1
debug = true
@ -19,41 +58,3 @@ incremental = true
[profile.release-with-debug]
inherits = "release"
debug = true
[workspace]
members = [
"uidev",
"wgui",
"wlx-common",
"wayvr",
"wlx-capture",
"dash-frontend",
"wayvr-ipc",
"wayvrctl",
"scripts/prost_build",
]
resolver = "3"
[patch.crates-io]
vulkano = { git = "https://github.com/galister/vulkano.git", rev = "cf7f92867928a56ce16b376037c1120f2b167678" }
[workspace.dependencies]
anyhow = "1.0.100"
smol = "2.0.2"
glam = { version = "0.30.9", features = ["mint", "serde"] }
clap = { version = "4.5.53", features = ["derive"] }
xdg = "3.0.0"
idmap = "0.2.2"
idmap-derive = "0.2.22"
log = "0.4.29"
regex = "1.12.2"
rust-embed = "8.9.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.145"
slotmap = "1.1.1"
strum = { version = "0.27.2", features = ["derive"] }
vulkano = { version = "0.35.2", default-features = false, features = [
"macros",
] }
vulkano-shaders = "0.35.0"
wayland-client = { version = "0.31.11" }

View File

@ -8,26 +8,25 @@ authors = ["galister", "oo8dev"]
repository = "https://github.com/wlx-team/wayvr"
[dependencies]
wayvr-ipc = { path = "../wayvr-ipc", default-features = false }
wgui = { path = "../wgui/" }
wlx-common = { path = "../wlx-common" }
anyhow.workspace = true
async-native-tls = "0.5.0"
chrono = "0.4.42"
glam = { workspace = true, features = ["mint", "serde"] }
http-body-util = "0.1.3"
hyper = { version = "1.8.1", features = ["client", "http1", "http2"] }
keyvalues-parser = { git = "https://github.com/CosmicHorrorDev/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" }
log.workspace = true
xdg.workspace = true
rust-embed.workspace = true
serde = { workspace = true, features = ["rc"] }
serde_json.workspace = true
strum.workspace = true
chrono = "0.4.42"
keyvalues-parser = { git = "https://github.com/CosmicHorrorDev/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" }
smol = { workspace = true }
hyper = { version = "1.8.1", features = ["client", "http1", "http2"] }
http-body-util = "0.1.3"
async-native-tls = "0.5.0"
smol-hyper = "0.1.1"
strum.workspace = true
uuid.workspace = true
wayvr-ipc = { path = "../wayvr-ipc", default-features = false }
wgui = { path = "../wgui/" }
wlx-common = { path = "../wlx-common" }
xdg.workspace = true
[features]
default = ["monado"]

View File

@ -1,6 +1,6 @@
<layout>
<elements>
<div id="list" gap="8" flex_wrap="wrap">
<div id="list" gap="8" flex_wrap="wrap" align_self="baseline">
<!-- filled-in at runtime -->
</div>
</elements>

View File

@ -1,7 +1,7 @@
<layout>
<elements>
<div flex_direction="column">
<div id="list_parent" gap="8" flex_direction="row" flex_wrap="wrap" overflow_y="scroll"/>
<div id="list_parent" gap="8" flex_direction="row" flex_wrap="wrap" />
</div>
<div flex_direction="row" gap="4">
<Button id="btn_refresh" tooltip="REFRESH" width="32" height="32" sprite_src_builtin="dashboard/refresh.svg" />

View File

@ -7,10 +7,7 @@
"label_desc"
-->
<template name="Cell">
<rectangle
border="2"
color="~color_bg_translucent"
border_color="~color_accent"
<Button
padding="8"
round="8"
flex_direction="column"
@ -18,9 +15,9 @@
width="256"
align_items="center"
align_self="start">
<image id="image_preview" width="100%" height="128"/>
<image id="image_preview" width="100%" height="128" round="6"/>
<label id="label_title" wrap="1" weight="bold"/>
<label id="label_author" wrap="1"/>
</rectangle>
</Button>
</template>
</layout>

View File

@ -393,7 +393,7 @@ impl<T: 'static> Frontend<T> {
.widgets
.cast_as::<WidgetSprite>(self.widgets.id_sprite_titlebar_icon)?;
sprite.set_content(
&mut common,
common.alterables,
Some(CustomGlyphData::from_assets(&self.globals, AssetPath::BuiltIn(icon))?),
);
}

View File

@ -1,9 +1,8 @@
use crate::util::{networking::http_client, steam_utils::AppID};
use anyhow::Context;
use serde::Deserialize;
use wlx_common::{async_executor::AsyncExecutor, cache_dir};
use crate::util::{http_client, steam_utils::AppID};
pub struct CoverArt {
// can be empty in case if data couldn't be fetched (use a fallback image then)
pub compressed_image_data: Vec<u8>,

View File

@ -1,5 +1,4 @@
pub mod cached_fetcher;
pub mod http_client;
pub mod networking;
pub mod pactl_wrapper;
pub mod popup_manager;

View File

@ -0,0 +1,14 @@
use wgui::{globals::WguiGlobals, renderer_vk::text::custom_glyph::CustomGlyphData};
use wlx_common::async_executor::AsyncExecutor;
use crate::util::networking::http_client;
pub async fn fetch_to_glyph_data(
globals: &WguiGlobals,
executor: &AsyncExecutor,
url: &str,
) -> anyhow::Result<CustomGlyphData> {
let res = http_client::get(executor, url).await?;
let glyph_data = CustomGlyphData::from_bytes_raster(globals, url, &res.data)?;
Ok(glyph_data)
}

View File

@ -1,3 +1,5 @@
pub mod http_client;
pub mod image_fetch;
pub mod skymap_catalog;
// pub const WAYVR_ROOT_URL: &'static str = "https://wayvr.org";

View File

@ -2,9 +2,16 @@
use serde::Deserialize;
use wlx_common::async_executor::AsyncExecutor;
use crate::util::{http_client, networking};
use crate::util::networking::{self, WAYVR_SKYMAPS_ROOT, http_client};
pub type SkymapUuid = String;
pub type SkymapUuid = uuid::Uuid;
pub enum SkymapResolution {
Res2k,
Res4k,
Res8k,
Res16k,
}
#[derive(Clone, Debug, Deserialize)]
pub struct SkymapCatalogEntryFiles {
@ -15,6 +22,30 @@ pub struct SkymapCatalogEntryFiles {
pub preview: String,
}
impl SkymapCatalogEntryFiles {
pub fn get_url_preview(&self) -> String {
format!("{}/files/{}", WAYVR_SKYMAPS_ROOT, self.preview)
}
pub fn get_filename_from_res(&self, res: SkymapResolution) -> Option<&String> {
match res {
SkymapResolution::Res2k => Some(&self.size_2k),
SkymapResolution::Res4k => self.size_4k.as_ref(),
SkymapResolution::Res8k => self.size_8k.as_ref(),
SkymapResolution::Res16k => self.size_16k.as_ref(),
}
}
// example result: "https://wayvr.org/skymaps/files/my_skymap_8k.png"
pub fn get_url_from_res(&self, res: SkymapResolution) -> Option<String> {
let Some(filename) = self.get_filename_from_res(res) else {
return None;
};
Some(format!("{}/files/{}", WAYVR_SKYMAPS_ROOT, filename))
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct SkymapCatalogEntry {
pub uuid: SkymapUuid,

View File

@ -4,6 +4,7 @@ use wgui::{
i18n::Translation,
layout::{Layout, WidgetID},
parser::{Fetchable, ParseDocumentParams},
renderer_vk::text::custom_glyph::CustomGlyphData,
task::Tasks,
};
use wlx_common::async_executor::AsyncExecutor;
@ -11,7 +12,10 @@ use wlx_common::async_executor::AsyncExecutor;
use crate::{
frontend::{FrontendTask, FrontendTasks},
util::{
networking::{self},
networking::{
self,
skymap_catalog::{SkymapCatalogEntry, SkymapUuid},
},
popup_manager::{MountPopupOnceParams, PopupHolder},
wgui_simple,
},
@ -28,6 +32,12 @@ pub struct Params<'a> {
enum Task {
SetSkymapCatalog(anyhow::Result<networking::skymap_catalog::SkymapCatalog>),
SetSkymapPreview((SkymapUuid, Option<CustomGlyphData>)),
}
struct MountedCell {
skymap_uuid: SkymapUuid,
view: views::skymap_list_cell::View,
}
pub struct View {
@ -36,7 +46,8 @@ pub struct View {
id_loading: WidgetID,
globals: WguiGlobals,
tasks: Tasks<Task>,
mounted_cells: Vec<views::skymap_list_cell::View>,
mounted_cells: Vec<MountedCell>,
executor: AsyncExecutor,
}
impl View {
@ -61,9 +72,22 @@ impl View {
tasks,
globals: par.globals.clone(),
mounted_cells: Vec::new(),
executor: par.executor.clone(),
})
}
async fn request_skymap_preview(
globals: WguiGlobals,
executor: AsyncExecutor,
entry: SkymapCatalogEntry,
tasks: Tasks<Task>,
) {
let glyph_data = networking::image_fetch::fetch_to_glyph_data(&globals, &executor, &entry.files.get_url_preview())
.await
.ok();
tasks.push(Task::SetSkymapPreview((entry.uuid, glyph_data)));
}
fn mount_catalog(
&mut self,
layout: &mut Layout,
@ -80,12 +104,23 @@ impl View {
let id_list = parser_state.fetch_widget(&layout.state, "list")?.id;
for entry in catalog.entries {
let view_cell = views::skymap_list_cell::View::new(views::skymap_list_cell::Params {
id_parent: id_list,
layout,
entry,
})?;
self.mounted_cells.push(view_cell);
let task = View::request_skymap_preview(
self.globals.clone(),
self.executor.clone(),
entry.clone(),
self.tasks.clone(),
);
self.mounted_cells.push(MountedCell {
skymap_uuid: entry.uuid.clone(),
view: views::skymap_list_cell::View::new(views::skymap_list_cell::Params {
id_parent: id_list,
layout,
entry,
})?,
});
self.executor.spawn(task).detach();
}
Ok(())
@ -107,6 +142,15 @@ impl View {
)?,
}
}
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)?;
}
}
}
}
Ok(())

View File

@ -1,9 +1,11 @@
use wgui::{
assets::AssetPath,
event::EventAlterables,
i18n::Translation,
layout::{Layout, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState},
widget::label::WidgetLabel,
renderer_vk::text::custom_glyph::CustomGlyphData,
widget::{image::WidgetImage, label::WidgetLabel},
};
use crate::util::{networking, wgui_simple};
@ -17,6 +19,8 @@ pub struct Params<'a> {
pub struct View {
#[allow(dead_code)]
parser_state: ParserState,
id_loading: WidgetID,
id_image_preview: WidgetID,
}
impl View {
@ -45,12 +49,28 @@ impl View {
);
}
wgui_simple::create_loading(wgui_simple::CreateLoadingParams {
let id_loading = wgui_simple::create_loading(wgui_simple::CreateLoadingParams {
layout: par.layout,
parent_id: id_image_preview,
with_text: false,
})?;
Ok(Self { parser_state })
Ok(Self {
parser_state,
id_loading,
id_image_preview,
})
}
pub fn set_image(&mut self, layout: &mut Layout, content: Option<CustomGlyphData>) -> anyhow::Result<()> {
layout.remove_widget(self.id_loading);
let mut alt = EventAlterables::default();
{
let mut image_preview = layout.state.widgets.cast_as::<WidgetImage>(self.id_image_preview)?;
image_preview.set_content(&mut alt, content);
}
layout.process_alterables(alt)?;
Ok(())
}
}

View File

@ -83,7 +83,7 @@ sysinfo = { version = "0.37" }
thiserror = "2.0"
tracing = "0.1.43"
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
uuid = { version = "1.19.0", features = ["fast-rng", "v4"] }
uuid = { workspace = true }
wayland-client = { workspace = true }
winit = { version = "0.30.12", optional = true }
xcb = { version = "1.6.0", features = [

View File

@ -527,9 +527,9 @@ pub fn apply_custom_command<T>(
.context("Could not load content from supplied path.")?;
if let Some(mut sprite) = pair.widget.get_as::<WidgetSprite>() {
sprite.set_content(&mut com, Some(data));
sprite.set_content(com.alterables, Some(data));
} else if let Some(mut image) = pair.widget.get_as::<WidgetImage>() {
image.set_content(&mut com, Some(data));
image.set_content(com.alterables, Some(data));
} else {
anyhow::bail!("No <sprite> or <image> with such id.");
}

View File

@ -105,7 +105,7 @@ where
.widgets
.get_as::<WidgetSprite>(self.top_sprite_id)
{
sprite.set_content(common, Some(new.sprite.clone()));
sprite.set_content(common.alterables, Some(new.sprite.clone()));
}
}

View File

@ -129,6 +129,11 @@ impl EventAlterables {
self.dirty_widgets.push(widget_id);
}
pub fn mark_dirty_and_redraw(&mut self, widget_id: WidgetID) {
self.mark_dirty(widget_id);
self.mark_redraw();
}
pub fn mark_tick(&mut self, widget_id: WidgetID) {
self.widgets_to_tick.insert(widget_id);
}
@ -174,8 +179,7 @@ impl CallbackDataCommon<'_> {
// helper functions
pub fn mark_widget_dirty(&mut self, id: WidgetID) {
self.alterables.mark_dirty(id);
self.alterables.mark_redraw();
self.alterables.mark_dirty_and_redraw(id);
}
pub fn globals(&self) -> RefMut<'_, globals::Globals> {

View File

@ -4,7 +4,7 @@ use slotmap::Key;
use crate::{
drawing::{self, ImagePrimitive, PrimitiveExtent},
event::CallbackDataCommon,
event::EventAlterables,
globals::Globals,
layout::WidgetID,
renderer_vk::text::custom_glyph::CustomGlyphData,
@ -44,13 +44,13 @@ impl WidgetImage {
)
}
pub fn set_content(&mut self, common: &mut CallbackDataCommon, content: Option<CustomGlyphData>) {
pub fn set_content(&mut self, alterables: &mut EventAlterables, content: Option<CustomGlyphData>) {
if self.params.glyph_data == content {
return;
}
self.params.glyph_data = content;
common.mark_widget_dirty(self.id);
alterables.mark_dirty_and_redraw(self.id);
}
pub fn get_content(&self) -> Option<CustomGlyphData> {

View File

@ -5,7 +5,7 @@ use slotmap::Key;
use crate::{
drawing::{self, PrimitiveExtent},
event::CallbackDataCommon,
event::{CallbackDataCommon, EventAlterables},
globals::Globals,
layout::WidgetID,
renderer_vk::text::{
@ -49,13 +49,13 @@ impl WidgetSprite {
self.params.color
}
pub fn set_content(&mut self, common: &mut CallbackDataCommon, content: Option<CustomGlyphData>) {
pub fn set_content(&mut self, alterables: &mut EventAlterables, content: Option<CustomGlyphData>) {
if self.params.glyph_data == content {
return;
}
self.params.glyph_data = content;
common.mark_widget_dirty(self.id);
alterables.mark_dirty_and_redraw(self.id);
}
pub fn get_content(&self) -> Option<CustomGlyphData> {