Implement deleting recordings

This commit is contained in:
Elias Projahn 2025-03-30 11:22:50 +02:00
parent 83789709ad
commit 109e17e5e4
3 changed files with 74 additions and 4 deletions

View file

@ -69,4 +69,5 @@ menu edit_menu {
item (_("_Add to playlist"), "recording.add-to-playlist")
item (_("Edit _recording"), "recording.edit-recording")
item (_("Edit _tracks"), "recording.edit-tracks")
item (_("_Delete from library"), "recording.delete")
}

View file

@ -13,7 +13,7 @@ use adw::{
prelude::*,
subclass::prelude::*,
};
use anyhow::{anyhow, Context, Result};
use anyhow::{anyhow, Context, Error, Result};
use chrono::prelude::*;
use diesel::{dsl::exists, prelude::*, sql_types, QueryDsl, SqliteConnection};
use formatx::formatx;
@ -1513,6 +1513,44 @@ impl Library {
Ok(())
}
pub fn delete_recording_and_tracks(&self, recording_id: &str) -> Result<()> {
let connection = &mut *self.imp().connection.get().unwrap().lock().unwrap();
let tracks = tracks::table
.filter(tracks::recording_id.eq(recording_id))
.load::<tables::Track>(connection)?;
// Delete from library first to avoid orphan tracks in case of file
// system related errors.
connection.transaction::<(), Error, _>(|connection| {
for track in &tracks {
diesel::delete(track_works::table)
.filter(track_works::track_id.eq(&track.track_id))
.execute(connection)?;
diesel::delete(tracks::table)
.filter(tracks::track_id.eq(&track.track_id))
.execute(connection)?;
}
diesel::delete(recordings::table)
.filter(recordings::recording_id.eq(recording_id))
.execute(connection)?;
Ok(())
})?;
let library_path = PathBuf::from(self.folder());
for track in tracks {
fs::remove_file(library_path.join(&track.path))?;
}
self.changed();
Ok(())
}
pub fn create_album(
&self,
name: TranslatedString,

View file

@ -1,7 +1,8 @@
use std::cell::OnceCell;
use adw::prelude::*;
use gettextrs::gettext;
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
use gtk::{gio, glib, subclass::prelude::*};
use crate::{
db::models::Recording, editor::recording::RecordingEditor, library::Library, player::Player,
@ -9,7 +10,7 @@ use crate::{
mod imp {
use super::*;
use crate::editor::tracks::TracksEditor;
use crate::{editor::tracks::TracksEditor, util};
#[derive(Debug, Default, gtk::CompositeTemplate)]
#[template(file = "data/ui/recording_tile.blp")]
@ -85,8 +86,38 @@ mod imp {
})
.build();
let obj = self.obj().to_owned();
let delete_action = gio::ActionEntry::builder("delete")
.activate(move |_, _, _| {
let dialog = adw::AlertDialog::builder()
.heading(&gettext("Delete recording?"))
.body(&gettext("The recording will be removed from your music library and the corresponding audio files will be deleted. This action cannot be undone."))
.build();
dialog.add_response("delete", &gettext("Delete"));
dialog.set_response_appearance("delete", adw::ResponseAppearance::Destructive);
dialog.add_response("cancel", &gettext("Cancel"));
dialog.set_default_response(Some("cancel"));
dialog.set_close_response("cancel");
let obj = obj.clone();
glib::spawn_future_local(async move {
if dialog.choose_future(&obj).await == "delete" {
if let Err(err) = obj.imp().library.get().unwrap().delete_recording_and_tracks(&obj.recording().recording_id) {
util::error_toast("Failed to delete recording", err, obj.imp().toast_overlay.get().unwrap());
}
}
});
})
.build();
let actions = gio::SimpleActionGroup::new();
actions.add_action_entries([append_action, edit_recording_action, edit_tracks_action]);
actions.add_action_entries([
append_action,
edit_recording_action,
edit_tracks_action,
delete_action,
]);
self.obj().insert_action_group("recording", Some(&actions));
}
}