fix: mod updates applying after launch and not before

This commit is contained in:
LynithDev 2026-09-14 21:03:34 +02:00
parent 6ceba7480f
commit 84bbf29882
3 changed files with 34 additions and 79 deletions

View file

@ -247,15 +247,14 @@ fn content(
}
let answers = choices.read();
let mut chosen = Vec::new();
for update in &all {
match answers
.get(&row_key(update))
.copied()
.unwrap_or_default()
{
RowChoice::Update => {
proceed_dispatch.apply_package_update(update.clone());
}
RowChoice::Update => chosen.push(update.clone()),
RowChoice::Skip => {}
RowChoice::SkipVersion => proceed_dispatch
.skip_package_update(
@ -264,7 +263,7 @@ fn content(
),
}
}
proceed_dispatch.close_package_updates();
proceed_dispatch.proceed_package_updates(chosen);
})
.child(Icon::new(IconType::DownloadCloud02).size(15.))
.text("Proceed"),

View file

@ -846,6 +846,12 @@ impl Actions {
});
}
pub fn proceed_package_updates(&self, chosen: Vec<oneclient_core::BrowserPackageUpdate>) {
self.with_engine(move |state| {
state.notifications.proceed_package_updates(chosen)
});
}
pub fn close_package_updates(&self) {
self.with_engine(|state| state.notifications.close_package_updates());
}
@ -1536,7 +1542,10 @@ impl Actions {
else {
return;
};
self.prompt_package_updates(group).await;
let chosen = self.prompt_package_updates(group).await;
if !chosen.is_empty() {
self.apply_updates_for_launch(state, &chosen).await;
}
}
}
}
@ -1619,6 +1628,8 @@ impl Actions {
.finish_grouped_as_actions(&mut app.inbox, session_id, spec);
});
super::invalidate_cluster_queries().await;
if applied > 0 {
super::invalidate_cluster_queries().await;
}
@ -1664,7 +1675,10 @@ impl Actions {
let _ = wait.await;
}
async fn prompt_package_updates(&self, group: PackageUpdateGroup) {
async fn prompt_package_updates(
&self,
group: PackageUpdateGroup,
) -> Vec<oneclient_core::BrowserPackageUpdate> {
let (done, wait) = tokio::sync::oneshot::channel();
self.with_engine(move |state| {
@ -1672,71 +1686,7 @@ impl Actions {
state.center_open = false;
});
let _ = wait.await;
}
pub fn apply_package_update(&self, update: oneclient_core::BrowserPackageUpdate) {
let actions = self.clone();
spawn_forever(async move {
let Ok(state) = launcher::state() else { return };
let events = state.services.events.clone();
let session = oneclient_events::GroupedProgressSession::start(
&events,
format!("Updating {}", update.display_name),
);
let child = session.child(
update.display_name.clone(),
1,
oneclient_events::TaskCategory::Packages,
);
let result = oneclient_core::apply_browser_package_update(
&update,
Some(&child),
&state.services.content(),
)
.await;
child.finish();
let session_id = session.detach();
let spec = match &result {
Ok(_) => NotificationSpec {
title: "Updated".to_string(),
body: format!(
"{} is now on {}",
update.display_name, update.latest_version_name
),
level: Level::Info,
icon: Some(IconType::DownloadCloud02),
progress: None,
actions: Vec::new(),
},
Err(err) => NotificationSpec {
title: "Update failed".to_string(),
body: err.to_string(),
level: Level::Error,
icon: None,
progress: None,
actions: Vec::new(),
},
};
actions.with_engine(|app| {
app.notifications
.finish_grouped_as_actions(&mut app.inbox, session_id, Some(spec));
});
// A failed update stays in the list so the user can retry
if result.is_ok() {
actions.with_engine(|app| {
app.notifications
.resolve_package_update(update.cluster_id, &update.hash);
});
super::invalidate_cluster_queries().await;
}
});
wait.await.unwrap_or_default()
}
/// The package stays marked out of date only the modal stops asking and

View file

@ -225,7 +225,7 @@ pub struct NotificationState {
/// Resumes the launch that opened the update modal
/// Held here not by the launch task
/// because every way the modal can end goes through this state
package_updates_done: Option<oneshot::Sender<()>>,
package_updates_done: Option<oneshot::Sender<Vec<BrowserPackageUpdate>>>,
optional_mods_done: Option<oneshot::Sender<()>>,
}
@ -388,7 +388,7 @@ impl NotificationState {
pub fn open_package_updates(
&mut self,
groups: Vec<PackageUpdateGroup>,
done: Option<oneshot::Sender<()>>,
done: Option<oneshot::Sender<Vec<BrowserPackageUpdate>>>,
) {
let groups: Vec<PackageUpdateGroup> = groups
.into_iter()
@ -397,19 +397,25 @@ impl NotificationState {
if groups.is_empty() {
if let Some(done) = done {
let _ = done.send(());
let _ = done.send(Vec::new());
}
return;
}
// A second modal would strand the first launch so release the old continuation first
self.finish_package_updates();
self.finish_package_updates(Vec::new());
self.package_updates = Some(groups);
self.package_updates_done = done;
}
pub fn close_package_updates(&mut self) {
self.finish_package_updates();
self.finish_package_updates(Vec::new());
}
/// The launch applies these itself so the game starts on the versions the
/// player just picked rather than racing them
pub fn proceed_package_updates(&mut self, chosen: Vec<BrowserPackageUpdate>) {
self.finish_package_updates(chosen);
}
/// Applying and skipping are both answers either drops the row and can close the modal
@ -426,16 +432,16 @@ impl NotificationState {
groups.retain(|group| !group.packages.is_empty());
if groups.is_empty() {
self.finish_package_updates();
self.finish_package_updates(Vec::new());
}
}
/// Safe to call when nothing is open so every exit path can call it unconditionally
fn finish_package_updates(&mut self) {
fn finish_package_updates(&mut self, chosen: Vec<BrowserPackageUpdate>) {
self.package_updates = None;
if let Some(done) = self.package_updates_done.take() {
// A send failure means the launch task is gone nothing left to resume
let _ = done.send(());
let _ = done.send(chosen);
}
}