Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show download sizes of in the example page #4841

Merged
merged 4 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ criterion = "0.5"
crossbeam = "0.8"
directories-next = "2"
document-features = "0.2"
ehttp = "0.3.1"
ehttp = "0.4.0"
enumset = "1.0.12"
env_logger = { version = "0.10", default-features = false }
ewebsock = "0.4.0"
Expand Down
3 changes: 2 additions & 1 deletion crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ impl App {
}

pub fn set_examples_manifest_url(&mut self, url: String) {
self.state.set_examples_manifest_url(url);
self.state
.set_examples_manifest_url(&self.re_ui.egui_ctx, url);
}

pub fn build_info(&self) -> &re_build_info::BuildInfo {
Expand Down
4 changes: 2 additions & 2 deletions crates/re_viewer/src/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ pub struct AppState {
}

impl AppState {
pub fn set_examples_manifest_url(&mut self, url: String) {
self.welcome_screen.set_examples_manifest_url(url);
pub fn set_examples_manifest_url(&mut self, egui_ctx: &egui::Context, url: String) {
self.welcome_screen.set_examples_manifest_url(egui_ctx, url);
}

pub fn app_options(&self) -> &AppOptions {
Expand Down
125 changes: 94 additions & 31 deletions crates/re_viewer/src/ui/welcome_screen/example_page.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use egui::{NumExt as _, Ui};

use ehttp::{fetch, Request};
use poll_promise::Promise;

use re_log_types::LogMsg;
use re_smart_channel::ReceiveSet;
use re_viewer_context::SystemCommandSender;
Expand Down Expand Up @@ -46,13 +46,24 @@ const THUMBNAIL_RADIUS: f32 = 4.0;
/// For layout purposes, each example spans multiple cells in the grid. This structure is used to
/// track the rectangle that spans the block of cells used for the corresponding example, so hover/
/// click can be detected.
#[derive(Debug)]
struct ExampleDescLayout {
desc: ExampleDesc,
rect: egui::Rect,

/// We do an async HEAD request to get the size of the RRD file
/// so we can show it to the user.
rrd_byte_size_promise: Promise<Option<u64>>,
}

impl ExampleDescLayout {
fn new(egui_ctx: &egui::Context, desc: ExampleDesc) -> Self {
ExampleDescLayout {
rrd_byte_size_promise: load_file_size(egui_ctx, desc.rrd_url.clone()),
desc,
rect: egui::Rect::NOTHING,
}
}

/// Saves the top left corner of the hover/click area for this example.
fn set_top_left(&mut self, pos: egui::Pos2) {
self.rect.min = pos;
Expand All @@ -74,15 +85,6 @@ impl ExampleDescLayout {
}
}

impl From<ExampleDesc> for ExampleDescLayout {
fn from(desc: ExampleDesc) -> Self {
ExampleDescLayout {
desc,
rect: egui::Rect::NOTHING,
}
}
}

type ManifestJson = Vec<ExampleDesc>;
type Manifest = Vec<ExampleDescLayout>;
type ManifestPromise = Promise<Result<Manifest, LoadError>>;
Expand All @@ -103,16 +105,67 @@ impl std::fmt::Display for LoadError {
}
}

fn load_manifest(url: String) -> ManifestPromise {
fn load_manifest(egui_ctx: &egui::Context, url: String) -> ManifestPromise {
let (sender, promise) = Promise::new();
let egui_ctx = egui_ctx.clone(); // So we can wake up the ui thread

fetch(Request::get(url), move |response| match response {
Ok(response) => sender.send(
serde_json::from_slice::<ManifestJson>(&response.bytes)
.map(|examples| examples.into_iter().map(ExampleDescLayout::from).collect())
.map_err(LoadError::Deserialize),
),
Err(err) => sender.send(Err(LoadError::Fetch(err))),
fetch(Request::get(url), move |response| {
match response {
Ok(response) => sender.send(
serde_json::from_slice::<ManifestJson>(&response.bytes)
.map(|examples| {
examples
.into_iter()
.map(|example| ExampleDescLayout::new(&egui_ctx, example))
.collect()
})
.map_err(LoadError::Deserialize),
),
Err(err) => sender.send(Err(LoadError::Fetch(err))),
}
egui_ctx.request_repaint();
});

promise
}

/// Do a HEAD request to get the size of a file.
///
/// In case of an error, it is logged as DEBUG and
/// the promise is resolved to `None`.
fn load_file_size(egui_ctx: &egui::Context, url: String) -> Promise<Option<u64>> {
let (sender, promise) = Promise::new();
let egui_ctx = egui_ctx.clone(); // So we can wake up the ui thread

let request = Request {
method: "HEAD".into(),
..Request::get(url.clone())
};

fetch(request, move |response| {
match response {
Ok(response) => {
if response.ok {
let headers = &response.headers;
let content_length = headers
.get("content-length")
.or_else(|| headers.get("x-goog-stored-content-length"))
.and_then(|s| s.parse::<u64>().ok());
sender.send(content_length);
} else {
re_log::debug!(
"Failed to load file size of {url:?}: {} {}",
response.status,
response.status_text
);
}
}
Err(err) => {
re_log::debug!("Failed to load file size of {url:?}: {err}");
sender.send(None);
}
}
egui_ctx.request_repaint();
});

promise
Expand Down Expand Up @@ -166,10 +219,10 @@ impl Default for ExamplePage {
}

impl ExamplePage {
pub fn set_manifest_url(&mut self, url: String) {
pub fn set_manifest_url(&mut self, egui_ctx: &egui::Context, url: String) {
if self.manifest_url != url {
self.manifest_url = url.clone();
self.examples = Some(load_manifest(url));
self.examples = Some(load_manifest(egui_ctx, url));
}
}

Expand All @@ -182,7 +235,7 @@ impl ExamplePage {
) -> WelcomeScreenResponse {
let examples = self
.examples
.get_or_insert_with(|| load_manifest(self.manifest_url.clone()));
.get_or_insert_with(|| load_manifest(ui.ctx(), self.manifest_url.clone()));

let Some(examples) = examples.ready_mut() else {
ui.spinner();
Expand Down Expand Up @@ -278,7 +331,7 @@ impl ExamplePage {
ui.vertical(|ui| {
example_description(
ui,
&example.desc,
example,
example.hovered(ui, self.id),
);

Expand Down Expand Up @@ -374,17 +427,27 @@ fn example_thumbnail(
}
}

fn example_description(ui: &mut Ui, example: &ExampleDesc, hovered: bool) {
ui.label(
egui::RichText::new(example.title.clone())
.strong()
.line_height(Some(22.0))
.text_style(re_ui::ReUi::welcome_screen_body()),
);
fn example_description(ui: &mut Ui, example: &ExampleDescLayout, hovered: bool) {
let desc = &example.desc;

let title = egui::RichText::new(desc.title.clone())
.strong()
.line_height(Some(22.0))
.text_style(re_ui::ReUi::welcome_screen_body());

ui.horizontal(|ui| {
ui.label(title);

if let Some(Some(size)) = example.rrd_byte_size_promise.ready().cloned() {
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.label(re_format::format_bytes(size as f64));
});
}
});

ui.add_space(4.0);

let mut desc_text = egui::RichText::new(example.description.clone()).line_height(Some(19.0));
let mut desc_text = egui::RichText::new(desc.description.clone()).line_height(Some(19.0));
if hovered {
desc_text = desc_text.strong();
}
Expand Down
4 changes: 2 additions & 2 deletions crates/re_viewer/src/ui/welcome_screen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ impl Default for WelcomeScreen {
}

impl WelcomeScreen {
pub fn set_examples_manifest_url(&mut self, url: String) {
self.example_page.set_manifest_url(url);
pub fn set_examples_manifest_url(&mut self, egui_ctx: &egui::Context, url: String) {
self.example_page.set_manifest_url(egui_ctx, url);
}

/// Welcome screen shown in place of the viewport when no data is loaded.
Expand Down
1 change: 1 addition & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ skip = [
{ name = "cargo_metadata" }, # Older version used by ply-rs. It's small, and it's build-time only!
{ name = "cfg_aliases" }, # Tiny macro-only crate. Winit and other use older version than us.
{ name = "core-graphics" }, # old version via arboard
{ name = "ehttp" }, # Will go away with next egui update
{ name = "foreign-types-shared" }, # used for cocoa bindings. wgpu uses newer than eframe.
{ name = "foreign-types" }, # used for cocoa bindings. wgpu uses newer than eframe.
{ name = "hashbrown" }, # Old version used by polar-rs
Expand Down
Loading