Skip to content
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
2 changes: 2 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ trash = {version = "=5.2.6"}
percent-encoding = {version = "=2.3.2"}
url = {version = "=2.5.8", features = ["serde"]}
uuid = {version = "=1.23.1", features = ["serde", "v4"]}
windows-sys = {version = "=0.61.2", features = ["Win32_Foundation", "Win32_Storage_FileSystem"]}

# util (codegen/macro)
anyhow = {version = "=1.0.102"}
Expand Down
21 changes: 13 additions & 8 deletions packages/oneclient_app/src/components/generic_prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use oneclient_java::JAVA_CHOICE_DOWNLOAD;

use crate::components::{Button, OverlayPopup};
use crate::hooks::{use_dispatch, use_notifications_snapshot};
use crate::microsoft_java::MICROSOFT_JAVA_CHOICE_INSTALL;
use crate::notifications::PendingPromptView;
use crate::theme::colors;
use crate::ui::border_all_color;
Expand All @@ -15,7 +16,9 @@ use crate::updater::UPDATE_CHOICE_INSTALL;
const CARD_BG: Color = Color::from_rgb(26, 34, 41);

fn claimed_elsewhere(prompt: &PendingPromptView) -> bool {
prompt.has_choice(JAVA_CHOICE_DOWNLOAD) || prompt.has_choice(UPDATE_CHOICE_INSTALL)
prompt.has_choice(JAVA_CHOICE_DOWNLOAD)
|| prompt.has_choice(UPDATE_CHOICE_INSTALL)
|| prompt.has_choice(MICROSOFT_JAVA_CHOICE_INSTALL)
}

#[derive(PartialEq)]
Expand Down Expand Up @@ -149,15 +152,17 @@ mod tests {
}

#[test]
fn the_two_rich_overlays_keep_their_own_prompts() {
assert!(claimed_elsewhere(&prompt(vec![Choice::primary(
fn the_rich_overlays_keep_their_own_prompts() {
for id in [
JAVA_CHOICE_DOWNLOAD,
"Download",
)])));
assert!(claimed_elsewhere(&prompt(vec![Choice::primary(
UPDATE_CHOICE_INSTALL,
"Download",
)])));
MICROSOFT_JAVA_CHOICE_INSTALL,
] {
assert!(
claimed_elsewhere(&prompt(vec![Choice::primary(id, "Download")])),
"{id} has its own overlay"
);
}
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::ui::border_all_color;

fn providers() -> Vec<(JavaVendor, &'static str)> {
vec![
(JavaVendor::Microsoft, "Microsoft Build of OpenJDK"),
(JavaVendor::Zulu, "Azul Zulu"),
(JavaVendor::Adoptium, "Eclipse Temurin"),
(JavaVendor::Corretto, "Amazon Corretto"),
Expand Down
189 changes: 189 additions & 0 deletions packages/oneclient_app/src/components/microsoft_java_prompt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
use std::time::Duration;

use freya::prelude::*;
use oneclient_events::Answer;

use crate::components::{Button, Icon, IconType, OverlayPopup};
use crate::hooks::{use_dispatch, use_notifications_snapshot};
use crate::microsoft_java::{MICROSOFT_JAVA_CHOICE_INSTALL, MICROSOFT_JAVA_CHOICE_NEVER};
use crate::theme::colors;
use crate::ui::border_all_color;

const CARD_BG: Color = Color::from_rgb(26, 34, 41);

const HOLD_SECONDS: u8 = 3;

#[derive(PartialEq)]
pub struct MicrosoftJavaPromptOverlay;

impl Component for MicrosoftJavaPromptOverlay {
fn render(&self) -> impl IntoElement {
let snapshot = use_notifications_snapshot();
let dispatch = use_dispatch();
let remaining = use_state(|| HOLD_SECONDS);

let showing = snapshot
.pending_prompt
.as_ref()
.is_some_and(|prompt| prompt.has_choice(MICROSOFT_JAVA_CHOICE_INSTALL));

use_side_effect_with_deps(&showing, move |&showing| {
let mut remaining = remaining;

if !showing {
remaining.set(HOLD_SECONDS);
return;
}

spawn(async move {
let mut remaining = remaining;
for step in (0..HOLD_SECONDS).rev() {
tokio::time::sleep(Duration::from_secs(1)).await;

// Re-armed while this was sleeping so a newer prompt owns the
// hold now and this countdown is stale
if { *remaining.peek() } != step + 1 {
return;
}

remaining.set(step);
}
});
});

let Some(prompt) = snapshot.pending_prompt.clone() else {
return rect().into_element();
};

if !prompt.has_choice(MICROSOFT_JAVA_CHOICE_INSTALL) {
return rect().into_element();
}

let held = *remaining.read();
let locked = held > 0;

let dismiss_label = prompt
.dismiss
.clone()
.unwrap_or_else(|| "Cancel".to_string());
let never_label = prompt
.choice(MICROSOFT_JAVA_CHOICE_NEVER)
.map(|choice| choice.label.clone())
.unwrap_or_else(|| "Don't ask again".to_string());
let install_label = prompt
.choice(MICROSOFT_JAVA_CHOICE_INSTALL)
.map(|choice| choice.label.clone())
.unwrap_or_else(|| "Proceed".to_string());

let close = dispatch.clone();
let cancel = dispatch.clone();
let never = dispatch.clone();
let accept = dispatch.clone();

OverlayPopup::new()
// Closing from the backdrop is a dismissal too so it waits as well
.on_close(move |_| {
if !locked {
close.dismiss_prompt();
}
})
.child(
rect()
.width(Size::window_percent(100.))
.height(Size::window_percent(100.))
.center()
.child(
rect()
.vertical()
.width(Size::px(440.))
.max_width(Size::window_percent(90.))
.spacing(14.)
.padding(Gaps::new_all(20.))
.corner_radius(CornerRadius::new_all(14.))
.background(CARD_BG)
.border(border_all_color(1., colors::component_border()))
.child(
rect()
.horizontal()
.cross_align(Alignment::Center)
.spacing(10.)
.child(
Icon::new(IconType::DownloadCloud02)
.size(20.)
.color(colors::brand()),
)
.child(
label()
.text(prompt.title.clone())
.font_size(16.)
.font_weight(FontWeight::SEMI_BOLD)
.color(colors::fg_primary()),
),
)
.child(
label()
.text(prompt.question.clone())
.font_size(12.)
.max_lines(6)
.width(Size::fill())
.color(colors::fg_secondary()),
)
.child(
rect()
.horizontal()
.width(Size::fill())
.cross_align(Alignment::Center)
.main_align(Alignment::SpaceBetween)
.child(
label()
.text(if locked {
held.to_string()
} else {
String::new()
})
.font_size(12.)
.color(colors::fg_secondary()),
)
.child(
rect()
.horizontal()
.spacing(8.)
.child(
Button::new()
.secondary()
.disabled(locked)
.on_press(move |_| cancel.dismiss_prompt())
.text(dismiss_label),
)
.child(
Button::new()
.secondary()
.disabled(locked)
.on_press(move |_| {
never.answer_prompt(Answer::new(
MICROSOFT_JAVA_CHOICE_NEVER,
))
})
.text(never_label),
)
.child(
Button::new()
.primary()
.on_press(move |_| {
accept.answer_prompt(Answer::new(
MICROSOFT_JAVA_CHOICE_INSTALL,
))
})
.child(
Icon::new(IconType::DownloadCloud02)
.size(14.),
)
.text(install_label),
),
),
),
),
)
.into_element()
}
}
2 changes: 2 additions & 0 deletions packages/oneclient_app/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod icons;
mod java_install_manager;
mod generic_prompt;
mod java_prompt;
mod microsoft_java_prompt;
mod link_confirm;
mod local_image;
mod log_viewer;
Expand Down Expand Up @@ -62,6 +63,7 @@ pub use icons::{Icon, IconTint, IconType};
pub use java_install_manager::JavaInstallManager;
pub use generic_prompt::GenericPromptOverlay;
pub use java_prompt::JavaPromptOverlay;
pub use microsoft_java_prompt::MicrosoftJavaPromptOverlay;
pub use link_confirm::ConfirmLinkOverlay;
pub use local_image::LocalImage;
pub use markdown::{Markdown, MarkdownStyle};
Expand Down
5 changes: 3 additions & 2 deletions packages/oneclient_app/src/components/overlay_popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use freya::{
use crate::hooks::use_overlay_claim;

const SCRIM_ALPHA: f32 = 90.;
const SCRIM_MIN_ALPHA: u8 = 1;

/// Overlay level of a top level popup. Its scrim sits two levels below it.
pub const OVERLAY_BASE_LEVEL: u8 = 12;
Expand Down Expand Up @@ -116,7 +117,7 @@ impl Component for OverlayPopup {
});

let scrim_alpha = if self.backdrop { SCRIM_ALPHA } else { 0. };
let alpha = (fade.read().value() * scrim_alpha) as u8;
let alpha = ((fade.read().value() * scrim_alpha) as u8).max(SCRIM_MIN_ALPHA);

rect()
.layer(Layer::Overlay)
Expand All @@ -130,7 +131,7 @@ impl Component for OverlayPopup {
.height(Size::window_percent(100.))
.layer(Layer::OverlayLevel(self.overlay_level.saturating_sub(2)))
.background(Color::from_argb(alpha, 0, 0, 0))
.on_press(move |_| {
.on_all_press(move |_| {
if let Some(on_close) = scrim_close.as_ref() {
on_close.call(());
}
Expand Down
22 changes: 20 additions & 2 deletions packages/oneclient_app/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use tokio::sync::mpsc;

use crate::hooks::PumpSignal;
use crate::notifications::{MESSAGE_TOAST_TTL, PendingPromptView};
use crate::state::{AppChannel, AppState, LoginProgress};
use crate::state::{AppChannel, AppState, LoginProgress, StorageScanProgress};

/// Quiet period before log lines are written without it every line wakes the log view
const GAME_LOG_FLUSH: Duration = Duration::from_millis(120);
Expand Down Expand Up @@ -127,6 +127,7 @@ impl EventPump {
let mut logs: Vec<(i64, String)> = Vec::new();
let mut failed: Option<(i64, String)> = None;
let mut login: Option<Option<LoginProgress>> = None;
let mut storage_scan: Option<Option<StorageScanProgress>> = None;
let mut sync_complete = false;

for event in batch {
Expand All @@ -148,7 +149,6 @@ impl EventPump {
cluster_id,
message,
}) => failed = Some((cluster_id, message)),
// Lifted out so it never reaches the engine the sign-in modal renders it inline
Event::Progress(ProgressEvent::Update {
id,
ref label,
Expand All @@ -161,6 +161,18 @@ impl EventPump {
total,
}));
}
Event::Progress(ProgressEvent::Update {
id,
ref label,
current,
total,
}) if id == oneclient_core::storage::STORAGE_SCAN_PROGRESS => {
storage_scan = Some((current < total).then(|| StorageScanProgress {
label: label.clone(),
current,
total,
}));
}
other => engine_events.push(other),
}
}
Expand Down Expand Up @@ -197,6 +209,12 @@ impl EventPump {
.microsoft_login = progress;
}

if let Some(progress) = storage_scan {
self.station
.write_channel(AppChannel::StorageScan)
.storage_scan = progress;
}

if !engine_events.is_empty() {
folded.touched_engine = true;
let mut guard = self.station.write_channel(AppChannel::Notifications);
Expand Down
Loading
Loading