diff --git a/musicus/res/ui/medium_preview.ui b/musicus/res/ui/medium_preview.ui
new file mode 100644
index 0000000..f6c3ed2
--- /dev/null
+++ b/musicus/res/ui/medium_preview.ui
@@ -0,0 +1,51 @@
+
+
+
+
+
+
diff --git a/musicus/src/import/import_screen.rs b/musicus/src/import/import_screen.rs
index 1b7ae4a..78e9c33 100644
--- a/musicus/src/import/import_screen.rs
+++ b/musicus/src/import/import_screen.rs
@@ -78,7 +78,10 @@ impl ImportScreen {
.build();
row.connect_activated(clone!(@weak this => move |_| {
- debug!("Medium selected: {}", medium.name);
+ let medium = medium.clone();
+ spawn!(@clone this, async move {
+ push!(this.handle, MediumPreview, (this.session.clone(), medium.clone())).await;
+ });
}));
this.matching_list.append(&row);
diff --git a/musicus/src/import/medium_preview.rs b/musicus/src/import/medium_preview.rs
new file mode 100644
index 0000000..6323204
--- /dev/null
+++ b/musicus/src/import/medium_preview.rs
@@ -0,0 +1,103 @@
+use super::medium_editor::MediumEditor;
+use crate::navigator::{NavigationHandle, Screen};
+use crate::widgets::Widget;
+use gettextrs::gettext;
+use glib::clone;
+use gtk::prelude::*;
+use gtk_macros::get_widget;
+use libadwaita::prelude::*;
+use log::debug;
+use musicus_backend::db::Medium;
+use musicus_backend::import::ImportSession;
+use std::rc::Rc;
+use std::sync::Arc;
+
+/// A dialog for presenting the selected medium when importing music.
+pub struct MediumPreview {
+ handle: NavigationHandle<()>,
+ session: Arc,
+ widget: gtk::Box,
+}
+
+impl Screen<(Arc, Medium), ()> for MediumPreview {
+ /// Create a new medium preview screen.
+ fn new((session, medium): (Arc, Medium), handle: NavigationHandle<()>) -> Rc {
+ // Create UI
+
+ let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/medium_preview.ui");
+
+ get_widget!(builder, gtk::Box, widget);
+ get_widget!(builder, gtk::Button, back_button);
+ get_widget!(builder, gtk::Box, medium_box);
+ get_widget!(builder, gtk::Label, name_label);
+
+ let this = Rc::new(Self {
+ handle,
+ session,
+ widget,
+ });
+
+ // Connect signals and callbacks
+
+ back_button.connect_clicked(clone!(@weak this => move |_| {
+ this.handle.pop(None);
+ }));
+
+ // Populate the widget
+
+ name_label.set_text(&medium.name);
+
+ for track_set in medium.tracks {
+ let recording = &track_set.recording;
+
+ let frame = gtk::FrameBuilder::new()
+ .margin_bottom(12)
+ .build();
+
+ let list = gtk::ListBoxBuilder::new()
+ .selection_mode(gtk::SelectionMode::None)
+ .build();
+
+ let header = libadwaita::ActionRowBuilder::new()
+ .activatable(false)
+ .title(&recording.work.get_title())
+ .subtitle(&recording.get_performers())
+ .build();
+
+ list.append(&header);
+
+ for track in track_set.tracks {
+ let mut parts = Vec::::new();
+ for part in &track.work_parts {
+ parts.push(track_set.recording.work.parts[*part].title.clone());
+ }
+
+ let title = if parts.is_empty() {
+ gettext("Unknown")
+ } else {
+ parts.join(", ")
+ };
+
+ let row = libadwaita::ActionRowBuilder::new()
+ .activatable(false)
+ .title(&title)
+ .subtitle(&track.path)
+ .margin_start(12)
+ .build();
+
+ list.append(&row);
+ }
+
+ frame.set_child(Some(&list));
+ medium_box.append(&frame);
+ }
+
+ this
+ }
+}
+
+impl Widget for MediumPreview {
+ fn get_widget(&self) -> gtk::Widget {
+ self.widget.clone().upcast()
+ }
+}