fix(app): ask before deleting offline copies

Delete season, Delete show, the episode's Done badge and the Downloads
page's Delete all went straight to removing the files, with no question
and no undo - gigabytes of a season a misclick away. They now share one
confirmation that names what goes and says the share keeps the files.
This commit is contained in:
nvrl committed 2026-10-12 22:38:40 +02:00
1 parent 603cc0c1a9
commit 77a926cbf5
3 files changed
+48 -8

No files matched your search

+41
View File
@@ -118,6 +118,9 @@ pub enum Action {
ResumeDownload(DownloadKey),
CancelDownload(DownloadKey),
RemoveDownload(DownloadKey, bool),
/// Ask whether to delete finished offline copies — of one episode, a
/// season or a show, named by the text.
DeleteOffline(Vec<DownloadKey>, String),
/// Crawl one share, or every share.
Crawl(Option<String>),
/// Stop the crawls still listing.
@@ -610,6 +613,9 @@ pub struct App {
pub downloads: Vec<DownloadItem>,
pub offline_files: std::collections::HashSet<DownloadKey>,
pub confirm_partial_delete: Option<DownloadKey>,
/// Finished offline copies the viewer asked to delete, and what they are
/// of, waiting on their say-so: gigabytes are one misclick away otherwise.
pub confirm_offline_delete: Option<(Vec<DownloadKey>, String)>,
/// A share the viewer asked to remove, waiting on their say-so.
pub confirm_remove_share: Option<String>,
/// Messages in the corner. See [`ui::toast`].
@@ -694,6 +700,7 @@ impl App {
downloads: Vec::new(),
offline_files: std::collections::HashSet::new(),
confirm_partial_delete: None,
confirm_offline_delete: None,
confirm_remove_share: None,
toasts: ui::toast::Toasts::default(),
pacer: Pacer::new(),
@@ -1404,6 +1411,11 @@ impl App {
self.engine.remove_download(key, false);
}
}
Action::DeleteOffline(keys, what) => {
if !keys.is_empty() {
self.confirm_offline_delete = Some((keys, what));
}
}
Action::SetMetadataConfig(config) => {
self.settings = config.clone();
self.engine.set_metadata_config(config);
@@ -1972,6 +1984,7 @@ impl eframe::App for App {
// also leave the page behind it.
let dialog = self.matcher.is_some()
|| self.confirm_partial_delete.is_some()
|| self.confirm_offline_delete.is_some()
|| self.confirm_remove_share.is_some()
|| self.shortcuts_open;
if !dialog {
@@ -2062,6 +2075,7 @@ impl eframe::App for App {
downloads,
offline_files,
confirm_partial_delete,
confirm_offline_delete,
confirm_remove_share,
shown_page,
..
@@ -2206,6 +2220,33 @@ impl eframe::App for App {
}
}
if let Some((keys, what)) = confirm_offline_delete.clone() {
let body = format!(
"{} deleted from this computer. The share keeps the files, and they can \
be downloaded again.",
match keys.len() {
1 => "The episode is".to_owned(),
count => format!("All {count} episodes are"),
}
);
match ui::confirm(
ctx,
"offline",
&format!("Delete the offline copy of {what}?"),
&body,
"Delete",
) {
ui::Answer::Confirmed => {
for key in keys {
engine.remove_download(key, false);
}
*confirm_offline_delete = None;
}
ui::Answer::Declined => *confirm_offline_delete = None,
ui::Answer::Pending => {}
}
}
if let Some(id) = confirm_remove_share.clone() {
let name = shares
.iter()
+1 -1
View File
@@ -227,7 +227,7 @@ fn buttons(ui: &mut egui::Ui, item: &DownloadItem, actions: &mut Vec<Action>) {
.on_hover_text("Delete the offline copy; keep the online source")
.clicked()
{
actions.push(Action::RemoveDownload(key(), false));
actions.push(Action::DeleteOffline(vec![key()], item.target.caption()));
}
}
}
+6 -7
View File
@@ -222,9 +222,10 @@ fn season_download(
.on_hover_text("Delete the offline copies; keep the online source")
.clicked()
{
for key in season_keys {
actions.push(Action::RemoveDownload(key, false));
}
actions.push(Action::DeleteOffline(
season_keys,
format!("{} {}", title.name, season.label()),
));
}
} else if ui
.button("Download season")
@@ -365,9 +366,7 @@ fn header(
.on_hover_text("Delete the offline copies; keep the online source")
.clicked()
{
for key in title_keys {
actions.push(Action::RemoveDownload(key, false));
}
actions.push(Action::DeleteOffline(title_keys, title.name.clone()));
}
} else if ui
.button("Download show")
@@ -941,7 +940,7 @@ fn download(
.on_hover_text("Available offline. Click to delete the copy; the share keeps the file.")
.clicked()
{
actions.push(Action::RemoveDownload(key, false));
actions.push(Action::DeleteOffline(vec![key], episode.label()));
}
return;
}