diff --git a/packages/oneclient_app/src/components/java_install_manager.rs b/packages/oneclient_app/src/components/java_install_manager.rs new file mode 100644 index 00000000..4a3c98c2 --- /dev/null +++ b/packages/oneclient_app/src/components/java_install_manager.rs @@ -0,0 +1,278 @@ +use freya::prelude::*; +use oneclient_core::java::{AvailableJava, JavaVendor}; + +use crate::components::{Button, Dropdown, Icon, IconType, OverlayPopup, ScrollArea}; +use crate::hooks::{provider_versions, use_provider_versions}; +use crate::theme::colors; +use crate::ui::border_all_color; + +fn providers() -> Vec<(JavaVendor, &'static str)> { + vec![ + (JavaVendor::Zulu, "Azul Zulu"), + (JavaVendor::Adoptium, "Eclipse Temurin"), + (JavaVendor::Corretto, "Amazon Corretto"), + (JavaVendor::Liberica, "BellSoft Liberica"), + ] +} + +/// Reusable "Install Java" picker. Lists downloadable runtimes per provider and +/// calls `on_install` with the chosen `(vendor, major)`. When `suggested` is set, +/// the matching major is pulled to the top and highlighted. +#[derive(PartialEq)] +pub struct JavaInstallManager { + suggested: Option, + on_install: Option>, + on_close: Option>, +} + +impl Default for JavaInstallManager { + fn default() -> Self { + Self::new() + } +} + +impl JavaInstallManager { + pub fn new() -> Self { + Self { + suggested: None, + on_install: None, + on_close: None, + } + } + + pub fn suggested(mut self, major: Option) -> Self { + self.suggested = major; + self + } + + pub fn on_install(mut self, handler: impl Into>) -> Self { + self.on_install = Some(handler.into()); + self + } + + pub fn on_close(mut self, handler: impl Into>) -> Self { + self.on_close = Some(handler.into()); + self + } +} + +impl Component for JavaInstallManager { + fn render(&self) -> impl IntoElement { + let providers = providers(); + let mut selected = use_state(|| 0usize); + let suggested = self.suggested; + + let idx = (*selected.read()).min(providers.len() - 1); + let (vendor, _) = providers[idx].clone(); + + let versions_query = use_provider_versions(vendor.clone()); + let (mut versions, loading) = provider_versions(&versions_query); + + // Pull the suggested major to the top so it reads as the default choice. + if let Some(major) = suggested { + versions.sort_by_key(|v| v.major != major); + } + + let provider_labels: Vec = + providers.iter().map(|(_, name)| name.to_string()).collect(); + let current_label = provider_labels[idx].clone(); + + let inner: Element = if loading { + status_text("Loading available versions...") + } else if versions.is_empty() { + status_text("No versions available from this provider.") + } else { + let mut area = ScrollArea::new() + .width(Size::fill()) + .height(Size::fill()) + .spacing(8.); + for available in versions { + let highlight = suggested == Some(available.major); + area = area.child( + VersionRow { + vendor: vendor.clone(), + available, + suggested: highlight, + on_install: self.on_install.clone(), + } + .into_element(), + ); + } + area.into_element() + }; + + let list = rect() + .width(Size::fill()) + .height(Size::px(280.)) + .child(inner) + .into_element(); + + let close_scrim = self.on_close.clone(); + let close_button = self.on_close.clone(); + + OverlayPopup::new() + .on_close(move |()| { + if let Some(handler) = &close_scrim { + handler.call(()); + } + }) + .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(16.) + .padding(Gaps::new_all(20.)) + .corner_radius(CornerRadius::new_all(16.)) + .background(colors::page_elevated()) + .border(border_all_color(1., colors::component_border())) + .child( + label() + .text("Install Java") + .font_size(18.) + .font_weight(FontWeight::SEMI_BOLD) + .color(colors::fg_primary()), + ) + .child( + rect() + .vertical() + .width(Size::fill()) + .spacing(6.) + .child( + label() + .text("Provider") + .font_size(11.) + .font_weight(FontWeight::MEDIUM) + .color(colors::fg_secondary()), + ) + .child( + Dropdown::new(current_label, provider_labels) + .width(Size::fill()) + .height(Size::px(34.)) + .on_select(move |i: usize| selected.set(i)), + ), + ) + .child(list) + .child( + rect() + .horizontal() + .width(Size::fill()) + .main_align(Alignment::End) + .child( + Button::new() + .ghost() + .on_press(move |_| { + if let Some(handler) = &close_button { + handler.call(()); + } + }) + .text("Close"), + ), + ), + ), + ) + .into_element() + } +} + +fn status_text(text: &'static str) -> Element { + rect() + .width(Size::fill()) + .padding(Gaps::new_symmetric(16., 4.)) + .child( + label() + .text(text) + .font_size(13.) + .color(colors::fg_secondary()), + ) + .into_element() +} + +#[derive(PartialEq)] +struct VersionRow { + vendor: JavaVendor, + available: AvailableJava, + suggested: bool, + on_install: Option>, +} + +impl Component for VersionRow { + fn render(&self) -> impl IntoElement { + let vendor = self.vendor.clone(); + let major = self.available.major; + let version = self.available.package.name.clone(); + let on_install = self.on_install.clone(); + + let mut title_row = rect() + .horizontal() + .cross_align(Alignment::Center) + .spacing(8.) + .child( + label() + .text(format!("Java {major}")) + .font_size(14.) + .font_weight(FontWeight::MEDIUM) + .color(colors::fg_primary()), + ); + + if self.suggested { + title_row = title_row.child( + rect() + .padding(Gaps::new_symmetric(2., 8.)) + .corner_radius(CornerRadius::new_all(6.)) + .background(colors::brand()) + .child( + label() + .text("Suggested") + .font_size(10.) + .font_weight(FontWeight::SEMI_BOLD) + .color(colors::fg_primary()), + ), + ); + } + + rect() + .horizontal() + .width(Size::fill()) + .content(Content::Flex) + .cross_align(Alignment::Center) + .spacing(12.) + .padding(Gaps::new_symmetric(10., 12.)) + .corner_radius(CornerRadius::new_all(10.)) + .background(colors::component_bg()) + .maybe(self.suggested, |el| { + el.border(border_all_color(1., colors::brand())) + }) + .child( + rect() + .vertical() + .width(Size::flex(1.0)) + .spacing(2.) + .child(title_row) + .child( + label() + .text(version) + .font_size(11.) + .max_lines(1) + .color(colors::fg_secondary()), + ), + ) + .child( + Button::new() + .primary() + .small() + .on_press(move |_| { + if let Some(handler) = &on_install { + handler.call((vendor.clone(), major)); + } + }) + .child(Icon::new(IconType::Download01).size(13.)) + .text("Install"), + ) + } +} diff --git a/packages/oneclient_app/src/components/java_prompt.rs b/packages/oneclient_app/src/components/java_prompt.rs new file mode 100644 index 00000000..eb4cb2eb --- /dev/null +++ b/packages/oneclient_app/src/components/java_prompt.rs @@ -0,0 +1,138 @@ +use freya::prelude::*; +use oneclient_core::java::JavaVendor; +use oneclient_core::notification::{PromptKind, UserChoice}; + +use crate::components::{Button, Icon, IconType, JavaInstallManager, OverlayPopup}; +use crate::hooks::{use_dispatch, use_notifications_snapshot}; +use crate::theme::colors; +use crate::ui::border_all_color; + +const CARD_BG: Color = Color::from_rgb(26, 34, 41); + +#[derive(PartialEq)] +pub struct JavaPromptOverlay; + +impl Component for JavaPromptOverlay { + fn render(&self) -> impl IntoElement { + // Hooks must run unconditionally, before any early return, so the hook + // count stays stable whether or not a Java prompt is pending. + let snapshot = use_notifications_snapshot(); + let dispatch = use_dispatch(); + let mut show_manager = use_state(|| false); + + let Some(prompt) = snapshot.pending_prompt.clone() else { + return rect().into_element(); + }; + + let PromptKind::JavaInstall { major } = prompt.kind else { + return rect().into_element(); + }; + + // Download opens the install manager with the required major highlighted. + if *show_manager.read() { + let install = dispatch.clone(); + return JavaInstallManager::new() + .suggested(Some(major)) + .on_install(move |(vendor, _row_major): (JavaVendor, u32)| { + // The launch needs `major`; the manager only picks the vendor. + install.answer_prompt(UserChoice::Install { vendor, major }); + show_manager.set(false); + }) + .on_close(move |()| show_manager.set(false)) + .into_element(); + } + + let close = dispatch.clone(); + let cancel = dispatch.clone(); + let folder = dispatch.clone(); + + let pick_folder = move |_| { + let dispatch = folder.clone(); + spawn(async move { + if let Some(handle) = rfd::AsyncFileDialog::new() + .set_title(format!("Select a Java {major} installation folder")) + .pick_folder() + .await + { + dispatch.answer_prompt(UserChoice::Folder(handle.path().to_path_buf())); + } + }); + }; + + OverlayPopup::new() + .on_close(move |_| close.answer_prompt(UserChoice::Cancel)) + .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::FolderDownload) + .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(4) + .width(Size::fill()) + .color(colors::fg_secondary()), + ) + .child( + rect() + .horizontal() + .width(Size::fill()) + .main_align(Alignment::End) + .spacing(8.) + .child( + Button::new() + .secondary() + .on_press(move |_| { + cancel.answer_prompt(UserChoice::Cancel) + }) + .text("Cancel"), + ) + .child( + Button::new() + .secondary() + .on_press(pick_folder) + .child(Icon::new(IconType::Folder).size(14.)) + .text("Choose folder"), + ) + .child( + Button::new() + .primary() + .on_press(move |_| show_manager.set(true)) + .child(Icon::new(IconType::DownloadCloud02).size(14.)) + .text("Download"), + ), + ), + ), + ) + .into_element() + } +} diff --git a/packages/oneclient_app/src/components/mod.rs b/packages/oneclient_app/src/components/mod.rs index 1da21773..3078dc22 100644 --- a/packages/oneclient_app/src/components/mod.rs +++ b/packages/oneclient_app/src/components/mod.rs @@ -9,6 +9,8 @@ mod context_menu; mod dropdown; mod dynamic_art; mod icons; +mod java_install_manager; +mod java_prompt; mod link_confirm; mod local_image; mod log_viewer; @@ -42,6 +44,8 @@ pub use context_menu::ContextMenu; pub use dropdown::Dropdown; pub use dynamic_art::DynamicArt; pub use icons::{Icon, IconType}; +pub use java_install_manager::JavaInstallManager; +pub use java_prompt::JavaPromptOverlay; pub use link_confirm::ConfirmLinkOverlay; pub use local_image::LocalImage; pub use log_viewer::LogViewer; diff --git a/packages/oneclient_app/src/layout/root_layout.rs b/packages/oneclient_app/src/layout/root_layout.rs index c8d6df51..9f886d72 100644 --- a/packages/oneclient_app/src/layout/root_layout.rs +++ b/packages/oneclient_app/src/layout/root_layout.rs @@ -2,7 +2,8 @@ use freya::prelude::*; use freya::router::*; use crate::components::{ - AccountSwitcher, ClusterUpdatePopup, NotificationCenter, StatusBar, Toasts, UpdatePromptOverlay, + AccountSwitcher, ClusterUpdatePopup, JavaPromptOverlay, NotificationCenter, StatusBar, Toasts, + UpdatePromptOverlay, }; use crate::routes::Route; use crate::theme; @@ -31,6 +32,7 @@ impl Component for RootLayout { .child(AccountSwitcher) .child(Toasts) .child(UpdatePromptOverlay) + .child(JavaPromptOverlay) .child(ClusterUpdatePopup) .child(StatusBar) } diff --git a/packages/oneclient_app/src/notifications.rs b/packages/oneclient_app/src/notifications.rs index 2915d5b0..1fffaa5d 100644 --- a/packages/oneclient_app/src/notifications.rs +++ b/packages/oneclient_app/src/notifications.rs @@ -312,15 +312,6 @@ impl NotificationState { kind, reply_tx, } => { - let entry_id = self.push_inbox( - inbox, - title.clone(), - question.clone(), - NotificationLevel::Info, - None, - false, - ); - self.push_ephemeral_toast(entry_id, MESSAGE_TOAST_TTL); let pending_prompt = Some(PendingPrompt { title: title.clone(), question: question.clone(), diff --git a/packages/oneclient_app/src/view/app/settings/java.rs b/packages/oneclient_app/src/view/app/settings/java.rs index bc8cda85..10ab58d6 100644 --- a/packages/oneclient_app/src/view/app/settings/java.rs +++ b/packages/oneclient_app/src/view/app/settings/java.rs @@ -1,33 +1,22 @@ use freya::prelude::*; -use oneclient_core::java::{AvailableJava, JavaRuntime, JavaVendor}; +use oneclient_core::java::{JavaRuntime, JavaVendor}; use super::settings_page; -use crate::components::{Button, Dropdown, Icon, IconType, OverlayPopup, ScrollArea}; -use crate::hooks::{ - BridgeDispatch, java_runtimes, provider_versions, use_dispatch, use_java_runtimes, - use_provider_versions, -}; +use crate::components::{Button, Icon, IconType, JavaInstallManager, ScrollArea}; +use crate::hooks::{BridgeDispatch, java_runtimes, use_dispatch, use_java_runtimes}; use crate::theme::colors; use crate::ui::border_all_color; use crate::view::app::settings::section_header; -fn providers() -> Vec<(JavaVendor, &'static str)> { - vec![ - (JavaVendor::Zulu, "Azul Zulu"), - (JavaVendor::Adoptium, "Eclipse Temurin"), - (JavaVendor::Corretto, "Amazon Corretto"), - (JavaVendor::Liberica, "BellSoft Liberica"), - ] -} - #[derive(PartialEq)] pub struct SettingsJava; impl Component for SettingsJava { fn render(&self) -> impl IntoElement { + let dispatch = use_dispatch(); let runtimes_query = use_java_runtimes(); let runtimes = java_runtimes(&runtimes_query); - let show_manager = use_state(|| false); + let mut show_manager = use_state(|| false); let mut shell = settings_page() .child(section_header("ADD RUNTIME")) @@ -36,7 +25,15 @@ impl Component for SettingsJava { .child(runtimes_table(runtimes)); if *show_manager.read() { - shell = shell.child(InstallManagerPopup { show_manager }.into_element()); + shell = shell.child( + JavaInstallManager::new() + .on_install(move |(vendor, major): (JavaVendor, u32)| { + dispatch.install_java_runtime(vendor, major); + show_manager.set(false); + }) + .on_close(move |()| show_manager.set(false)) + .into_element(), + ); } shell.into_element() @@ -249,185 +246,3 @@ fn remove_button(dispatch: BridgeDispatch, path: String) -> impl IntoElement { ) .into_element() } - -#[derive(PartialEq)] -struct InstallManagerPopup { - show_manager: State, -} - -impl Component for InstallManagerPopup { - fn render(&self) -> impl IntoElement { - let mut show_manager = self.show_manager; - let providers = providers(); - let mut selected = use_state(|| 0usize); - - let idx = (*selected.read()).min(providers.len() - 1); - let (vendor, _) = providers[idx].clone(); - - let versions_query = use_provider_versions(vendor.clone()); - let (versions, loading) = provider_versions(&versions_query); - - let provider_labels: Vec = - providers.iter().map(|(_, name)| name.to_string()).collect(); - let current_label = provider_labels[idx].clone(); - - let inner: Element = if loading { - status_text("Loading available versions...") - } else if versions.is_empty() { - status_text("No versions available from this provider.") - } else { - let mut area = ScrollArea::new() - .width(Size::fill()) - .height(Size::fill()) - .spacing(8.); - for available in versions { - area = area.child( - VersionRow { - vendor: vendor.clone(), - available, - show_manager, - } - .into_element(), - ); - } - area.into_element() - }; - - let list = rect() - .width(Size::fill()) - .height(Size::px(280.)) - .child(inner) - .into_element(); - - OverlayPopup::new() - .on_close(move |()| show_manager.set(false)) - .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(16.) - .padding(Gaps::new_all(20.)) - .corner_radius(CornerRadius::new_all(16.)) - .background(colors::page_elevated()) - .border(border_all_color(1., colors::component_border())) - .child( - label() - .text("Install Java") - .font_size(18.) - .font_weight(FontWeight::SEMI_BOLD) - .color(colors::fg_primary()), - ) - .child( - rect() - .vertical() - .width(Size::fill()) - .spacing(6.) - .child( - label() - .text("Provider") - .font_size(11.) - .font_weight(FontWeight::MEDIUM) - .color(colors::fg_secondary()), - ) - .child( - Dropdown::new(current_label, provider_labels) - .width(Size::fill()) - .height(Size::px(34.)) - .on_select(move |i: usize| selected.set(i)), - ), - ) - .child(list) - .child( - rect() - .horizontal() - .width(Size::fill()) - .main_align(Alignment::End) - .child( - Button::new() - .ghost() - .on_press(move |_| show_manager.set(false)) - .text("Close"), - ), - ), - ), - ) - .into_element() - } -} - -fn status_text(text: &'static str) -> Element { - rect() - .width(Size::fill()) - .padding(Gaps::new_symmetric(16., 4.)) - .child( - label() - .text(text) - .font_size(13.) - .color(colors::fg_secondary()), - ) - .into_element() -} - -#[derive(PartialEq)] -struct VersionRow { - vendor: JavaVendor, - available: AvailableJava, - show_manager: State, -} - -impl Component for VersionRow { - fn render(&self) -> impl IntoElement { - let dispatch = use_dispatch(); - let mut show_manager = self.show_manager; - let vendor = self.vendor.clone(); - let major = self.available.major; - let version = self.available.package.name.clone(); - - rect() - .horizontal() - .width(Size::fill()) - .content(Content::Flex) - .cross_align(Alignment::Center) - .spacing(12.) - .padding(Gaps::new_symmetric(10., 12.)) - .corner_radius(CornerRadius::new_all(10.)) - .background(colors::component_bg()) - .child( - rect() - .vertical() - .width(Size::flex(1.0)) - .spacing(2.) - .child( - label() - .text(format!("Java {major}")) - .font_size(14.) - .font_weight(FontWeight::MEDIUM) - .color(colors::fg_primary()), - ) - .child( - label() - .text(version) - .font_size(11.) - .max_lines(1) - .color(colors::fg_secondary()), - ), - ) - .child( - Button::new() - .primary() - .small() - .on_press(move |_| { - dispatch.install_java_runtime(vendor.clone(), major); - show_manager.set(false); - }) - .child(Icon::new(IconType::Download01).size(13.)) - .text("Install"), - ) - } -} diff --git a/packages/oneclient_core/src/game/launch.rs b/packages/oneclient_core/src/game/launch.rs index b9245167..9e4b3667 100644 --- a/packages/oneclient_core/src/game/launch.rs +++ b/packages/oneclient_core/src/game/launch.rs @@ -171,6 +171,7 @@ pub async fn launch_cluster( .as_ref() .map(|v| v.major_version) .ok_or(GameError::MissingJavaVersion)?; + JavaManager::prepare_java(state, major, search_for_java).await? }; diff --git a/packages/oneclient_core/src/java/manager.rs b/packages/oneclient_core/src/java/manager.rs index 41d6da59..5845a7f8 100644 --- a/packages/oneclient_core/src/java/manager.rs +++ b/packages/oneclient_core/src/java/manager.rs @@ -68,6 +68,9 @@ impl JavaManager { match services.notifier.prompt_java_install(major).await? { UserChoice::Accept => download_and_register(major, services).await, UserChoice::Folder(folder) => register_custom_java(&services.db, folder, major).await, + UserChoice::Install { vendor, .. } => { + Self::install_runtime_from(services, &vendor, major).await + } UserChoice::Cancel => Err(JavaError::Cancelled.into()), } } diff --git a/packages/oneclient_core/src/notification/data.rs b/packages/oneclient_core/src/notification/data.rs index dc8c5efb..80025d7b 100644 --- a/packages/oneclient_core/src/notification/data.rs +++ b/packages/oneclient_core/src/notification/data.rs @@ -179,6 +179,10 @@ pub enum UserChoice { Accept, Cancel, Folder(PathBuf), + Install { + vendor: crate::java::JavaVendor, + major: u32, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/packages/oneclient_core/src/notification/grouped.rs b/packages/oneclient_core/src/notification/grouped.rs index d9d2e9b9..4c2e1523 100644 --- a/packages/oneclient_core/src/notification/grouped.rs +++ b/packages/oneclient_core/src/notification/grouped.rs @@ -1,15 +1,33 @@ use std::sync::Arc; -use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use uuid::Uuid; -use super::data::{GroupedProgressEvent, TaskCategory}; use super::NotificationService; +use super::data::{GroupedProgressEvent, TaskCategory}; -#[derive(Clone)] struct SessionInner { session_id: Uuid, notifier: NotificationService, + ended: AtomicBool, +} + +impl SessionInner { + fn end(&self) { + if self.ended.swap(true, Ordering::Relaxed) { + return; + } + + self.notifier.send_grouped(GroupedProgressEvent::End { + session_id: self.session_id, + }); + } +} + +impl Drop for SessionInner { + fn drop(&mut self) { + self.end(); + } } struct ChildInner { @@ -42,6 +60,7 @@ impl GroupedProgressSession { inner: Arc::new(SessionInner { session_id, notifier: notifier.clone(), + ended: AtomicBool::new(false), }), } } @@ -56,12 +75,14 @@ impl GroupedProgressSession { if count == 0 { return; } - self.inner.notifier.send_grouped(GroupedProgressEvent::Expect { - session_id: self.inner.session_id, - category, - count, - total, - }); + self.inner + .notifier + .send_grouped(GroupedProgressEvent::Expect { + session_id: self.inner.session_id, + category, + count, + total, + }); } pub fn child( @@ -74,13 +95,15 @@ impl GroupedProgressSession { let label = label.into(); let total = total.max(1); - self.inner.notifier.send_grouped(GroupedProgressEvent::AddChild { - session_id: self.inner.session_id, - child_id, - label: label.clone(), - total, - category, - }); + self.inner + .notifier + .send_grouped(GroupedProgressEvent::AddChild { + session_id: self.inner.session_id, + child_id, + label: label.clone(), + total, + category, + }); GroupedProgressChild { inner: Arc::new(ChildInner { @@ -114,11 +137,7 @@ impl GroupedProgressSession { } pub fn finish(self) { - self.inner - .notifier - .send_grouped(GroupedProgressEvent::End { - session_id: self.inner.session_id, - }); + self.inner.end(); } } @@ -128,18 +147,28 @@ impl GroupedProgressChild { } pub fn set_phase(&self, phase: super::data::TaskPhase) { - if self.inner.finished.load(std::sync::atomic::Ordering::Relaxed) { + if self + .inner + .finished + .load(std::sync::atomic::Ordering::Relaxed) + { return; } - self.inner.notifier.send_grouped(GroupedProgressEvent::SetChildPhase { - session_id: self.inner.session_id, - child_id: self.inner.child_id, - phase, - }); + self.inner + .notifier + .send_grouped(GroupedProgressEvent::SetChildPhase { + session_id: self.inner.session_id, + child_id: self.inner.child_id, + phase, + }); } pub fn set_progress(&self, current: u64, total: Option) { - if self.inner.finished.load(std::sync::atomic::Ordering::Relaxed) { + if self + .inner + .finished + .load(std::sync::atomic::Ordering::Relaxed) + { return; } @@ -152,12 +181,14 @@ impl GroupedProgressChild { if total > stored { self.inner.total.store(total, Ordering::Relaxed); } - self.inner.notifier.send_grouped(GroupedProgressEvent::UpdateChild { - session_id: self.inner.session_id, - child_id: self.inner.child_id, - current, - total, - }); + self.inner + .notifier + .send_grouped(GroupedProgressEvent::UpdateChild { + session_id: self.inner.session_id, + child_id: self.inner.child_id, + current, + total, + }); } pub fn finish(&self) { @@ -169,10 +200,12 @@ impl GroupedProgressChild { return; } - self.inner.notifier.send_grouped(GroupedProgressEvent::FinishChild { - session_id: self.inner.session_id, - child_id: self.inner.child_id, - }); + self.inner + .notifier + .send_grouped(GroupedProgressEvent::FinishChild { + session_id: self.inner.session_id, + child_id: self.inner.child_id, + }); } } @@ -181,4 +214,3 @@ impl Drop for GroupedProgressChild { self.finish(); } } -