Add user preferences for random playback

This commit is contained in:
Elias Projahn 2022-04-08 19:59:49 +02:00
parent 3ae5727f39
commit 5c64bdef7e
14 changed files with 402 additions and 156 deletions

View file

@ -1,7 +1,11 @@
use gio::traits::SettingsExt;
use log::warn;
use musicus_database::Database; use musicus_database::Database;
use std::cell::RefCell; use std::{
use std::path::PathBuf; cell::{Cell, RefCell},
use std::rc::Rc; path::PathBuf,
rc::Rc,
};
use tokio::sync::{broadcast, broadcast::Sender}; use tokio::sync::{broadcast, broadcast::Sender};
pub use musicus_database as db; pub use musicus_database as db;
@ -55,6 +59,12 @@ pub struct Backend {
/// The player handling playlist and playback. This can be assumed to exist, when the state is /// The player handling playlist and playback. This can be assumed to exist, when the state is
/// set to BackendState::Ready. /// set to BackendState::Ready.
player: RefCell<Option<Rc<Player>>>, player: RefCell<Option<Rc<Player>>>,
/// Whether to keep playing random tracks after the playlist ends.
keep_playing: Cell<bool>,
/// Whether to choose full recordings for random playback.
play_full_recordings: Cell<bool>,
} }
impl Backend { impl Backend {
@ -73,6 +83,8 @@ impl Backend {
library_updated_sender, library_updated_sender,
database: RefCell::new(None), database: RefCell::new(None),
player: RefCell::new(None), player: RefCell::new(None),
keep_playing: Cell::new(false),
play_full_recordings: Cell::new(true),
} }
} }
@ -83,8 +95,12 @@ impl Backend {
/// Initialize the backend. A state callback should already have been registered using /// Initialize the backend. A state callback should already have been registered using
/// [`set_state_cb()`] to react to the result. /// [`set_state_cb()`] to react to the result.
pub fn init(&self) -> Result<()> { pub fn init(self: Rc<Self>) -> Result<()> {
self.init_library()?; self.keep_playing.set(self.settings.boolean("keep-playing"));
self.play_full_recordings
.set(self.settings.boolean("play-full-recordings"));
Rc::clone(&self).init_library()?;
match self.get_music_library_path() { match self.get_music_library_path() {
None => self.set_state(BackendState::NoMusicLibrary), None => self.set_state(BackendState::NoMusicLibrary),
@ -94,12 +110,68 @@ impl Backend {
Ok(()) Ok(())
} }
/// Whether to keep playing random tracks after the playlist ends.
pub fn keep_playing(&self) -> bool {
self.keep_playing.get()
}
/// Set whether to keep playing random tracks after the playlist ends.
pub fn set_keep_playing(self: Rc<Self>, keep_playing: bool) {
if let Err(err) = self.settings.set_boolean("keep-playing", keep_playing) {
warn!(
"The preference \"keep-playing\" could not be saved using GSettings. It will most \
likely not be available at the next startup. Error message: {}",
err
);
}
self.keep_playing.set(keep_playing);
self.update_track_generator();
}
/// Whether to choose full recordings for random playback.
pub fn play_full_recordings(&self) -> bool {
self.play_full_recordings.get()
}
/// Set whether to choose full recordings for random playback.
pub fn set_play_full_recordings(self: Rc<Self>, play_full_recordings: bool) {
if let Err(err) = self
.settings
.set_boolean("play-full-recordings", play_full_recordings)
{
warn!(
"The preference \"play-full-recordings\" could not be saved using GSettings. It \
will most likely not be available at the next startup. Error message: {}",
err
);
}
self.play_full_recordings.set(play_full_recordings);
self.update_track_generator();
}
/// Set the current state and notify the user interface. /// Set the current state and notify the user interface.
fn set_state(&self, state: BackendState) { fn set_state(&self, state: BackendState) {
if let Some(cb) = &*self.state_cb.borrow() { if let Some(cb) = &*self.state_cb.borrow() {
cb(state); cb(state);
} }
} }
/// Apply the current track generation settings.
fn update_track_generator(self: Rc<Self>) {
if let Some(player) = self.get_player() {
if self.keep_playing() {
if self.play_full_recordings() {
player.set_track_generator(Some(RandomRecordingGenerator::new(self)));
} else {
player.set_track_generator(Some(RandomTrackGenerator::new(self)));
}
} else {
player.set_track_generator(None::<RandomRecordingGenerator>);
}
}
}
} }
impl Default for Backend { impl Default for Backend {

View file

@ -1,6 +1,5 @@
use crate::{Backend, BackendState, Player, Result}; use crate::{Backend, BackendState, Player, Result};
use gio::prelude::*; use gio::prelude::*;
use glib::clone;
use log::warn; use log::warn;
use musicus_database::Database; use musicus_database::Database;
use std::path::PathBuf; use std::path::PathBuf;
@ -8,7 +7,7 @@ use std::rc::Rc;
impl Backend { impl Backend {
/// Initialize the music library if it is set in the settings. /// Initialize the music library if it is set in the settings.
pub(super) fn init_library(&self) -> Result<()> { pub(super) fn init_library(self: Rc<Self>) -> Result<()> {
let path = self.settings.string("music-library-path"); let path = self.settings.string("music-library-path");
if !path.is_empty() { if !path.is_empty() {
self.set_music_library_path_priv(PathBuf::from(path.to_string()))?; self.set_music_library_path_priv(PathBuf::from(path.to_string()))?;
@ -18,7 +17,7 @@ impl Backend {
} }
/// Set the path to the music library folder and connect to the database. /// Set the path to the music library folder and connect to the database.
pub fn set_music_library_path(&self, path: PathBuf) -> Result<()> { pub fn set_music_library_path(self: Rc<Self>, path: PathBuf) -> Result<()> {
if let Err(err) = self if let Err(err) = self
.settings .settings
.set_string("music-library-path", path.to_str().unwrap()) .set_string("music-library-path", path.to_str().unwrap())
@ -34,7 +33,7 @@ impl Backend {
} }
/// Set the path to the music library folder and and connect to the database. /// Set the path to the music library folder and and connect to the database.
pub fn set_music_library_path_priv(&self, path: PathBuf) -> Result<()> { pub fn set_music_library_path_priv(self: Rc<Self>, path: PathBuf) -> Result<()> {
self.set_state(BackendState::Loading); self.set_state(BackendState::Loading);
self.music_library_path.replace(Some(path.clone())); self.music_library_path.replace(Some(path.clone()));
@ -46,14 +45,10 @@ impl Backend {
self.database.replace(Some(Rc::clone(&database))); self.database.replace(Some(Rc::clone(&database)));
let player = Player::new(path); let player = Player::new(path);
// Keep adding random tracks in case the playlist ends.
player.set_generate_next_track_cb(clone!(@weak database => @default-panic, move || {
database.random_track().unwrap()
}));
self.player.replace(Some(player)); self.player.replace(Some(player));
Rc::clone(&self).update_track_generator();
self.set_state(BackendState::Ready); self.set_state(BackendState::Ready);
Ok(()) Ok(())

View file

@ -1,4 +1,4 @@
use crate::{Error, Result}; use crate::{Backend, Error, Result};
use glib::clone; use glib::clone;
use gstreamer_player::prelude::*; use gstreamer_player::prelude::*;
use musicus_database::Track; use musicus_database::Track;
@ -17,7 +17,7 @@ pub struct Player {
current_track: Cell<Option<usize>>, current_track: Cell<Option<usize>>,
playing: Cell<bool>, playing: Cell<bool>,
duration: Cell<u64>, duration: Cell<u64>,
generate_next_track_cb: RefCell<Option<Box<dyn Fn() -> Track>>>, track_generator: RefCell<Option<Box<dyn TrackGenerator>>>,
playlist_cbs: RefCell<Vec<Box<dyn Fn(Vec<Track>)>>>, playlist_cbs: RefCell<Vec<Box<dyn Fn(Vec<Track>)>>>,
track_cbs: RefCell<Vec<Box<dyn Fn(usize)>>>, track_cbs: RefCell<Vec<Box<dyn Fn(usize)>>>,
duration_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>, duration_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>,
@ -45,7 +45,7 @@ impl Player {
current_track: Cell::new(None), current_track: Cell::new(None),
playing: Cell::new(false), playing: Cell::new(false),
duration: Cell::new(0), duration: Cell::new(0),
generate_next_track_cb: RefCell::new(None), track_generator: RefCell::new(None),
playlist_cbs: RefCell::new(Vec::new()), playlist_cbs: RefCell::new(Vec::new()),
track_cbs: RefCell::new(Vec::new()), track_cbs: RefCell::new(Vec::new()),
duration_cbs: RefCell::new(Vec::new()), duration_cbs: RefCell::new(Vec::new()),
@ -146,8 +146,11 @@ impl Player {
result result
} }
pub fn set_generate_next_track_cb<F: Fn() -> Track + 'static>(&self, cb: F) { pub fn set_track_generator<G: TrackGenerator + 'static>(&self, generator: Option<G>) {
self.generate_next_track_cb.replace(Some(Box::new(cb))); self.track_generator.replace(match generator {
Some(generator) => Some(Box::new(generator)),
None => None,
});
} }
pub fn add_playlist_cb<F: Fn(Vec<Track>) + 'static>(&self, cb: F) { pub fn add_playlist_cb<F: Fn(Vec<Track>) + 'static>(&self, cb: F) {
@ -190,12 +193,17 @@ impl Player {
self.playing.get() self.playing.get()
} }
pub fn add_item(&self, item: Track) -> Result<()> { /// Add some items to the playlist.
pub fn add_items(&self, mut items: Vec<Track>) -> Result<()> {
if items.is_empty() {
return Ok(())
}
let was_empty = { let was_empty = {
let mut playlist = self.playlist.borrow_mut(); let mut playlist = self.playlist.borrow_mut();
let was_empty = playlist.is_empty(); let was_empty = playlist.is_empty();
playlist.push(item); playlist.append(&mut items);
was_empty was_empty
}; };
@ -282,8 +290,8 @@ impl Player {
} }
pub fn has_next(&self) -> bool { pub fn has_next(&self) -> bool {
if self.generate_next_track_cb.borrow().is_some() { if let Some(generator) = &*self.track_generator.borrow() {
true generator.has_next()
} else if let Some(current_track) = self.current_track.get() { } else if let Some(current_track) = self.current_track.get() {
let playlist = self.playlist.borrow(); let playlist = self.playlist.borrow();
current_track + 1 < playlist.len() current_track + 1 < playlist.len()
@ -294,13 +302,19 @@ impl Player {
pub fn next(&self) -> Result<()> { pub fn next(&self) -> Result<()> {
let current_track = self.current_track.get(); let current_track = self.current_track.get();
let cb = self.generate_next_track_cb.borrow(); let generator = self.track_generator.borrow();
if let Some(current_track) = current_track { if let Some(current_track) = current_track {
if current_track + 1 >= self.playlist.borrow().len() { if current_track + 1 >= self.playlist.borrow().len() {
if let Some(cb) = &*cb { if let Some(generator) = &*generator {
let new_track = cb(); let items = generator.next();
self.add_item(new_track)?; if !items.is_empty() {
self.add_items(items)?;
} else {
return Err(Error::Other(String::from(
"Track generator failed to generate next track.",
)));
}
} else { } else {
return Err(Error::Other(String::from("No existing next track."))); return Err(Error::Other(String::from("No existing next track.")));
} }
@ -309,9 +323,15 @@ impl Player {
self.set_track(current_track + 1)?; self.set_track(current_track + 1)?;
Ok(()) Ok(())
} else if let Some(cb) = &*cb { } else if let Some(generator) = &*generator {
let new_track = cb(); let items = generator.next();
self.add_item(new_track)?; if !items.is_empty() {
self.add_items(items)?;
} else {
return Err(Error::Other(String::from(
"Track generator failed to generate next track.",
)));
}
Ok(()) Ok(())
} else { } else {
@ -406,3 +426,58 @@ impl Player {
self.mpris.set_can_play(false); self.mpris.set_can_play(false);
} }
} }
/// Generator for new tracks to be appended to the playlist.
pub trait TrackGenerator {
/// Whether the generator will provide a next track if asked.
fn has_next(&self) -> bool;
/// Provide the next track.
///
/// This function should always return at least one track in a state where
/// `has_next()` returns `true`.
fn next(&self) -> Vec<Track>;
}
/// A track generator that generates one random track per call.
pub struct RandomTrackGenerator {
backend: Rc<Backend>,
}
impl RandomTrackGenerator {
pub fn new(backend: Rc<Backend>) -> Self {
Self { backend }
}
}
impl TrackGenerator for RandomTrackGenerator {
fn has_next(&self) -> bool {
true
}
fn next(&self) -> Vec<Track> {
vec![self.backend.db().random_track().unwrap()]
}
}
/// A track generator that returns the tracks of one random recording per call.
pub struct RandomRecordingGenerator {
backend: Rc<Backend>,
}
impl RandomRecordingGenerator {
pub fn new(backend: Rc<Backend>) -> Self {
Self { backend }
}
}
impl TrackGenerator for RandomRecordingGenerator {
fn has_next(&self) -> bool {
true
}
fn next(&self) -> Vec<Track> {
let recording = self.backend.db().random_recording().unwrap();
self.backend.db().get_tracks(&recording.id).unwrap()
}
}

View file

@ -76,7 +76,7 @@ impl PersonOrEnsemble {
} }
/// Database table data for a recording. /// Database table data for a recording.
#[derive(Insertable, Queryable, Debug, Clone)] #[derive(Insertable, Queryable, QueryableByName, Debug, Clone)]
#[table_name = "recordings"] #[table_name = "recordings"]
struct RecordingRow { struct RecordingRow {
pub id: String, pub id: String,
@ -201,6 +201,17 @@ impl Database {
Ok(recording) Ok(recording)
} }
/// Get a random recording from the database.
pub fn random_recording(&self) -> Result<Recording> {
let row = diesel::sql_query("SELECT * FROM recordings ORDER BY RANDOM() LIMIT 1")
.load::<RecordingRow>(&self.connection)?
.into_iter()
.next()
.ok_or(Error::Other("Failed to find random recording."))?;
self.get_recording_data(row)
}
/// Retrieve all available information on a recording from related tables. /// Retrieve all available information on a recording from related tables.
fn get_recording_data(&self, row: RecordingRow) -> Result<Recording> { fn get_recording_data(&self, row: RecordingRow) -> Result<Recording> {
let mut performance_descriptions: Vec<Performance> = Vec::new(); let mut performance_descriptions: Vec<Performance> = Vec::new();

View file

@ -5,5 +5,13 @@
<default>""</default> <default>""</default>
<summary>Path to the music library folder</summary> <summary>Path to the music library folder</summary>
</key> </key>
<key name="keep-playing" type="b">
<default>false</default>
<summary>Keep playing after the playlist ends</summary>
</key>
<key name="play-full-recordings" type="b">
<default>true</default>
<summary>Choose full recordings for random playback</summary>
</key>
</schema> </schema>
</schemalist> </schemalist>

View file

@ -5,7 +5,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: unnamed project\n" "Project-Id-Version: unnamed project\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-10 12:32+0100\n" "POT-Creation-Date: 2022-04-08 19:52+0200\n"
"PO-Revision-Date: 2022-02-10 12:34+0100\n" "PO-Revision-Date: 2022-02-10 12:34+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
@ -29,13 +29,13 @@ msgid "Loading"
msgstr "Lade…" msgstr "Lade…"
#: ../res/ui/medium_preview.ui:149 ../res/ui/source_selector.ui:101 #: ../res/ui/medium_preview.ui:149 ../res/ui/source_selector.ui:101
#: ../res/ui/medium_editor.ui:152 ../res/ui/medium_editor.ui:189 #: ../res/ui/medium_editor.ui:151 ../res/ui/medium_editor.ui:188
#: ../res/ui/editor.ui:68 #: ../res/ui/editor.ui:68
msgid "Error" msgid "Error"
msgstr "Fehler" msgstr "Fehler"
#: ../res/ui/medium_preview.ui:161 ../res/ui/source_selector.ui:113 #: ../res/ui/medium_preview.ui:161 ../res/ui/source_selector.ui:113
#: ../res/ui/medium_editor.ui:164 ../res/ui/editor.ui:80 #: ../res/ui/medium_editor.ui:163 ../res/ui/editor.ui:80
msgid "Try again" msgid "Try again"
msgstr "Nochmal versuchen" msgstr "Nochmal versuchen"
@ -43,29 +43,29 @@ msgstr "Nochmal versuchen"
msgid "Performance" msgid "Performance"
msgstr "Auftritt" msgstr "Auftritt"
#: ../res/ui/performance_editor.ui:55 #: ../res/ui/performance_editor.ui:52
msgid "Select a person" msgid "Select a person"
msgstr "Person auswählen" msgstr "Person auswählen"
#: ../res/ui/performance_editor.ui:59 ../res/ui/performance_editor.ui:72 #: ../res/ui/performance_editor.ui:56 ../res/ui/performance_editor.ui:69
#: ../res/ui/performance_editor.ui:92 ../res/ui/track_set_editor.ui:69 #: ../res/ui/performance_editor.ui:89 ../res/ui/track_set_editor.ui:67
#: ../res/ui/import_screen.ui:154 ../res/ui/preferences.ui:23 #: ../res/ui/import_screen.ui:160 ../res/ui/preferences.ui:23
#: ../res/ui/recording_editor.ui:83 ../res/ui/work_editor.ui:83 #: ../res/ui/recording_editor.ui:81 ../res/ui/work_editor.ui:81
#: ../src/import/source_selector.rs:51 ../src/screens/welcome.rs:56 #: ../src/import/source_selector.rs:51 ../src/screens/welcome.rs:56
#: ../src/preferences.rs:42 #: ../src/preferences.rs:44
msgid "Select" msgid "Select"
msgstr "Auswählen" msgstr "Auswählen"
#: ../res/ui/performance_editor.ui:68 #: ../res/ui/performance_editor.ui:65
msgid "Select an ensemble" msgid "Select an ensemble"
msgstr "Ensemble auswählen" msgstr "Ensemble auswählen"
#: ../res/ui/performance_editor.ui:81 #: ../res/ui/performance_editor.ui:78
msgid "Select a role" msgid "Select a role"
msgstr "Rolle auswählen" msgstr "Rolle auswählen"
#: ../res/ui/player_bar.ui:65 ../res/ui/player_screen.ui:97 #: ../res/ui/player_bar.ui:65 ../res/ui/player_screen.ui:97
#: ../res/ui/work_part_editor.ui:59 ../res/ui/work_editor.ui:92 #: ../res/ui/work_part_editor.ui:56 ../res/ui/work_editor.ui:90
msgid "Title" msgid "Title"
msgstr "Titel" msgstr "Titel"
@ -113,15 +113,15 @@ msgid "Select tracks"
msgstr "Tracks auswählen" msgstr "Tracks auswählen"
#: ../res/ui/track_set_editor.ui:51 ../res/ui/recording_editor.ui:18 #: ../res/ui/track_set_editor.ui:51 ../res/ui/recording_editor.ui:18
#: ../res/ui/recording_editor.ui:155 #: ../res/ui/recording_editor.ui:154
msgid "Recording" msgid "Recording"
msgstr "Aufnahme" msgstr "Aufnahme"
#: ../res/ui/track_set_editor.ui:65 #: ../res/ui/track_set_editor.ui:63
msgid "Select a recording" msgid "Select a recording"
msgstr "Aufnahme auswählen" msgstr "Aufnahme auswählen"
#: ../res/ui/track_set_editor.ui:89 ../src/screens/recording.rs:30 #: ../res/ui/track_set_editor.ui:88 ../src/screens/recording.rs:30
msgid "Tracks" msgid "Tracks"
msgstr "Tracks" msgstr "Tracks"
@ -133,31 +133,31 @@ msgstr "Werkabschnitt"
msgid "Matching metadata" msgid "Matching metadata"
msgstr "Passende Metadaten" msgstr "Passende Metadaten"
#: ../res/ui/import_screen.ui:66 #: ../res/ui/import_screen.ui:64
msgid "Loading…" msgid "Loading…"
msgstr "Lade…" msgstr "Lade…"
#: ../res/ui/import_screen.ui:87 #: ../res/ui/import_screen.ui:88
msgid "Error while searching for matching metadata" msgid "Error while searching for matching metadata"
msgstr "Fehler bei der Suche nach passenden Metadaten" msgstr "Fehler bei der Suche nach passenden Metadaten"
#: ../res/ui/import_screen.ui:110 #: ../res/ui/import_screen.ui:114
msgid "No matching metadata found" msgid "No matching metadata found"
msgstr "Keine passenden Metadaten gefunden" msgstr "Keine passenden Metadaten gefunden"
#: ../res/ui/import_screen.ui:136 #: ../res/ui/import_screen.ui:144
msgid "Manually add metadata" msgid "Manually add metadata"
msgstr "Metadaten manuell hinzufügen" msgstr "Metadaten manuell hinzufügen"
#: ../res/ui/import_screen.ui:150 #: ../res/ui/import_screen.ui:156
msgid "Select existing medium" msgid "Select existing medium"
msgstr "Existierendes Medium auswählen" msgstr "Existierendes Medium auswählen"
#: ../res/ui/import_screen.ui:163 #: ../res/ui/import_screen.ui:169
msgid "Add a new medium" msgid "Add a new medium"
msgstr "Neues Medium hinzufügen" msgstr "Neues Medium hinzufügen"
#: ../res/ui/import_screen.ui:167 #: ../res/ui/import_screen.ui:173
msgid "Add" msgid "Add"
msgstr "Hinzufügen" msgstr "Hinzufügen"
@ -165,22 +165,22 @@ msgstr "Hinzufügen"
msgid "Medium" msgid "Medium"
msgstr "Medium" msgstr "Medium"
#: ../res/ui/medium_editor.ui:75 #: ../res/ui/medium_editor.ui:73
msgid "Name of the medium" msgid "Name of the medium"
msgstr "Name des Mediums" msgstr "Name des Mediums"
#: ../res/ui/medium_editor.ui:99 #: ../res/ui/medium_editor.ui:98
msgid "Recordings" msgid "Recordings"
msgstr "Aufnahmen" msgstr "Aufnahmen"
#: ../res/ui/medium_editor.ui:201 ../res/ui/editor.ui:22 #: ../res/ui/medium_editor.ui:200 ../res/ui/editor.ui:22
#: ../src/import/source_selector.rs:50 ../src/screens/welcome.rs:55 #: ../src/import/source_selector.rs:50 ../src/screens/welcome.rs:55
#: ../src/preferences.rs:41 #: ../src/preferences.rs:43
msgid "Cancel" msgid "Cancel"
msgstr "Abbrechen" msgstr "Abbrechen"
#: ../res/ui/preferences.ui:11 ../src/editors/ensemble.rs:34 #: ../res/ui/preferences.ui:11 ../src/editors/ensemble.rs:35
#: ../src/editors/instrument.rs:34 ../src/editors/person.rs:38 #: ../src/editors/instrument.rs:35 ../src/editors/person.rs:39
msgid "General" msgid "General"
msgstr "Allgemein" msgstr "Allgemein"
@ -196,19 +196,41 @@ msgstr "Ordner der Musikbibliothek"
msgid "None selected" msgid "None selected"
msgstr "Keiner ausgewählt" msgstr "Keiner ausgewählt"
#: ../res/ui/preferences.ui:34
msgid "Playlist"
msgstr "Wiedergabeliste"
#: ../res/ui/preferences.ui:38
msgid "Keep playing"
msgstr "Weiter abspielen"
#: ../res/ui/preferences.ui:40
msgid "Whether to keep playing random tracks after the playlist ends."
msgstr "Nach dem Ende der Wiedergabeliste weiter im Zufallsmodus abspielen."
#: ../res/ui/preferences.ui:51
msgid "Choose full recordings"
msgstr "Komplette Aufnahmen abspielen"
#: ../res/ui/preferences.ui:53
msgid ""
"Whether to choose full recordings instead of single tracks for random "
"playback."
msgstr "Im Zufallsmodus vollständige Aufnahmen anstatt einzelner Tracks verwenden."
#: ../res/ui/recording_editor.ui:65 ../res/ui/work_editor.ui:65 #: ../res/ui/recording_editor.ui:65 ../res/ui/work_editor.ui:65
msgid "Overview" msgid "Overview"
msgstr "Überblick" msgstr "Überblick"
#: ../res/ui/recording_editor.ui:79 #: ../res/ui/recording_editor.ui:77
msgid "Select a work" msgid "Select a work"
msgstr "Werk auswählen" msgstr "Werk auswählen"
#: ../res/ui/recording_editor.ui:92 #: ../res/ui/recording_editor.ui:90
msgid "Comment" msgid "Comment"
msgstr "Kommentar" msgstr "Kommentar"
#: ../res/ui/recording_editor.ui:116 #: ../res/ui/recording_editor.ui:115
msgid "Performers" msgid "Performers"
msgstr "Interpreten" msgstr "Interpreten"
@ -216,20 +238,20 @@ msgstr "Interpreten"
msgid "Search …" msgid "Search …"
msgstr "Suchen…" msgstr "Suchen…"
#: ../res/ui/work_editor.ui:18 ../res/ui/work_editor.ui:182 #: ../res/ui/work_editor.ui:18 ../res/ui/work_editor.ui:181
#: ../src/editors/recording.rs:173 #: ../src/editors/recording.rs:173
msgid "Work" msgid "Work"
msgstr "Werk" msgstr "Werk"
#: ../res/ui/work_editor.ui:79 #: ../res/ui/work_editor.ui:77
msgid "Select a composer" msgid "Select a composer"
msgstr "Komponisten auswählen" msgstr "Komponisten auswählen"
#: ../res/ui/work_editor.ui:116 #: ../res/ui/work_editor.ui:115
msgid "Instruments" msgid "Instruments"
msgstr "Instrumente" msgstr "Instrumente"
#: ../res/ui/work_editor.ui:143 #: ../res/ui/work_editor.ui:142
msgid "Structure" msgid "Structure"
msgstr "Struktur" msgstr "Struktur"
@ -265,44 +287,44 @@ msgstr "Einstellungen"
msgid "About Musicus" msgid "About Musicus"
msgstr "Über Musicus" msgstr "Über Musicus"
#: ../src/editors/performance.rs:42 #: ../src/editors/performance.rs:43
msgid "Performer" msgid "Performer"
msgstr "Interpret" msgstr "Interpret"
#: ../src/editors/performance.rs:44 #: ../src/editors/performance.rs:45
msgid "Select either a person or an ensemble as a performer." msgid "Select either a person or an ensemble as a performer."
msgstr "Wählen Sie entweder eine Person oder ein Ensemble als Interpreten aus." msgstr "Wählen Sie entweder eine Person oder ein Ensemble als Interpreten aus."
#: ../src/editors/performance.rs:62 #: ../src/editors/performance.rs:64
msgid "Role" msgid "Role"
msgstr "Rolle" msgstr "Rolle"
#: ../src/editors/performance.rs:64 #: ../src/editors/performance.rs:66
msgid "Optionally, choose a role to specify what the performer does." msgid "Optionally, choose a role to specify what the performer does."
msgstr "" msgstr ""
"Wählen Sie optional eine Rolle aus, die angibt, was der Interpret macht." "Wählen Sie optional eine Rolle aus, die angibt, was der Interpret macht."
#: ../src/editors/ensemble.rs:31 ../src/editors/instrument.rs:31 #: ../src/editors/ensemble.rs:32 ../src/editors/instrument.rs:32
msgid "Name" msgid "Name"
msgstr "Name" msgstr "Name"
#: ../src/editors/ensemble.rs:65 #: ../src/editors/ensemble.rs:66
msgid "Failed to save ensemble!" msgid "Failed to save ensemble!"
msgstr "Ensemble konnte nicht gespeichert werden!" msgstr "Ensemble konnte nicht gespeichert werden!"
#: ../src/editors/instrument.rs:65 #: ../src/editors/instrument.rs:66
msgid "Failed to save instrument!" msgid "Failed to save instrument!"
msgstr "Instrument konnte nicht gespeichert werden!" msgstr "Instrument konnte nicht gespeichert werden!"
#: ../src/editors/person.rs:32 #: ../src/editors/person.rs:33
msgid "First name" msgid "First name"
msgstr "Vorname" msgstr "Vorname"
#: ../src/editors/person.rs:33 #: ../src/editors/person.rs:34
msgid "Last name" msgid "Last name"
msgstr "Nachname" msgstr "Nachname"
#: ../src/editors/person.rs:72 #: ../src/editors/person.rs:73
msgid "Failed to save person!" msgid "Failed to save person!"
msgstr "Person konnte nicht gespeichert werden!" msgstr "Person konnte nicht gespeichert werden!"
@ -310,8 +332,8 @@ msgstr "Person konnte nicht gespeichert werden!"
msgid "Composer" msgid "Composer"
msgstr "Komponist" msgstr "Komponist"
#: ../src/import/track_set_editor.rs:133 ../src/import/medium_preview.rs:171 #: ../src/import/track_set_editor.rs:133 ../src/import/medium_preview.rs:170
#: ../src/screens/medium.rs:74 ../src/screens/recording.rs:84 #: ../src/screens/medium.rs:72 ../src/screens/recording.rs:82
msgid "Unknown" msgid "Unknown"
msgstr "Unbekannt" msgstr "Unbekannt"
@ -339,11 +361,11 @@ msgstr "Person bearbeiten"
msgid "Delete person" msgid "Delete person"
msgstr "Person löschen" msgstr "Person löschen"
#: ../src/screens/recording.rs:55 #: ../src/screens/recording.rs:53
msgid "Edit recording" msgid "Edit recording"
msgstr "Aufnahme bearbeiten" msgstr "Aufnahme bearbeiten"
#: ../src/screens/recording.rs:65 #: ../src/screens/recording.rs:63
msgid "Delete recording" msgid "Delete recording"
msgstr "Aufnahme löschen" msgstr "Aufnahme löschen"
@ -357,7 +379,7 @@ msgstr ""
"Musicus wird dort eine neue Datenbank anlegen oder eine bereits existierende " "Musicus wird dort eine neue Datenbank anlegen oder eine bereits existierende "
"öffnen." "öffnen."
#: ../src/screens/welcome.rs:51 ../src/preferences.rs:37 #: ../src/screens/welcome.rs:51 ../src/preferences.rs:39
msgid "Select music library folder" msgid "Select music library folder"
msgstr "Ordner der Musikbibliothek auswählen" msgstr "Ordner der Musikbibliothek auswählen"
@ -369,15 +391,15 @@ msgstr "Werk bearbeiten"
msgid "Delete work" msgid "Delete work"
msgstr "Werk löschen" msgstr "Werk löschen"
#: ../src/screens/main.rs:196 #: ../src/screens/main.rs:200
msgid "Musicus" msgid "Musicus"
msgstr "Musicus" msgstr "Musicus"
#: ../src/screens/main.rs:198 #: ../src/screens/main.rs:202
msgid "The classical music player and organizer." msgid "The classical music player and organizer."
msgstr "Das Programm zum Abspielen und Organisieren von Klassik." msgstr "Das Programm zum Abspielen und Organisieren von Klassik."
#: ../src/screens/main.rs:200 #: ../src/screens/main.rs:204
msgid "Further information and source code" msgid "Further information and source code"
msgstr "Weitere Informationen und Quellcode" msgstr "Weitere Informationen und Quellcode"
@ -453,9 +475,6 @@ msgstr "Aufnahme auswählen"
#~ msgid "No works or recordings found." #~ msgid "No works or recordings found."
#~ msgstr "Keine Werke oder Aufnahmen gefunden." #~ msgstr "Keine Werke oder Aufnahmen gefunden."
#~ msgid "Add to playlist"
#~ msgstr "Zur Wiedergabeliste hinzufügen"
#~ msgid "Select a composer on the left." #~ msgid "Select a composer on the left."
#~ msgstr "Wählen Sie einen Komponisten aus." #~ msgstr "Wählen Sie einen Komponisten aus."

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-10 12:32+0100\n" "POT-Creation-Date: 2022-04-08 19:52+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -30,13 +30,13 @@ msgid "Loading"
msgstr "" msgstr ""
#: ../res/ui/medium_preview.ui:149 ../res/ui/source_selector.ui:101 #: ../res/ui/medium_preview.ui:149 ../res/ui/source_selector.ui:101
#: ../res/ui/medium_editor.ui:152 ../res/ui/medium_editor.ui:189 #: ../res/ui/medium_editor.ui:151 ../res/ui/medium_editor.ui:188
#: ../res/ui/editor.ui:68 #: ../res/ui/editor.ui:68
msgid "Error" msgid "Error"
msgstr "" msgstr ""
#: ../res/ui/medium_preview.ui:161 ../res/ui/source_selector.ui:113 #: ../res/ui/medium_preview.ui:161 ../res/ui/source_selector.ui:113
#: ../res/ui/medium_editor.ui:164 ../res/ui/editor.ui:80 #: ../res/ui/medium_editor.ui:163 ../res/ui/editor.ui:80
msgid "Try again" msgid "Try again"
msgstr "" msgstr ""
@ -44,29 +44,29 @@ msgstr ""
msgid "Performance" msgid "Performance"
msgstr "" msgstr ""
#: ../res/ui/performance_editor.ui:55 #: ../res/ui/performance_editor.ui:52
msgid "Select a person" msgid "Select a person"
msgstr "" msgstr ""
#: ../res/ui/performance_editor.ui:59 ../res/ui/performance_editor.ui:72 #: ../res/ui/performance_editor.ui:56 ../res/ui/performance_editor.ui:69
#: ../res/ui/performance_editor.ui:92 ../res/ui/track_set_editor.ui:69 #: ../res/ui/performance_editor.ui:89 ../res/ui/track_set_editor.ui:67
#: ../res/ui/import_screen.ui:154 ../res/ui/preferences.ui:23 #: ../res/ui/import_screen.ui:160 ../res/ui/preferences.ui:23
#: ../res/ui/recording_editor.ui:83 ../res/ui/work_editor.ui:83 #: ../res/ui/recording_editor.ui:81 ../res/ui/work_editor.ui:81
#: ../src/import/source_selector.rs:51 ../src/screens/welcome.rs:56 #: ../src/import/source_selector.rs:51 ../src/screens/welcome.rs:56
#: ../src/preferences.rs:42 #: ../src/preferences.rs:44
msgid "Select" msgid "Select"
msgstr "" msgstr ""
#: ../res/ui/performance_editor.ui:68 #: ../res/ui/performance_editor.ui:65
msgid "Select an ensemble" msgid "Select an ensemble"
msgstr "" msgstr ""
#: ../res/ui/performance_editor.ui:81 #: ../res/ui/performance_editor.ui:78
msgid "Select a role" msgid "Select a role"
msgstr "" msgstr ""
#: ../res/ui/player_bar.ui:65 ../res/ui/player_screen.ui:97 #: ../res/ui/player_bar.ui:65 ../res/ui/player_screen.ui:97
#: ../res/ui/work_part_editor.ui:59 ../res/ui/work_editor.ui:92 #: ../res/ui/work_part_editor.ui:56 ../res/ui/work_editor.ui:90
msgid "Title" msgid "Title"
msgstr "" msgstr ""
@ -114,15 +114,15 @@ msgid "Select tracks"
msgstr "" msgstr ""
#: ../res/ui/track_set_editor.ui:51 ../res/ui/recording_editor.ui:18 #: ../res/ui/track_set_editor.ui:51 ../res/ui/recording_editor.ui:18
#: ../res/ui/recording_editor.ui:155 #: ../res/ui/recording_editor.ui:154
msgid "Recording" msgid "Recording"
msgstr "" msgstr ""
#: ../res/ui/track_set_editor.ui:65 #: ../res/ui/track_set_editor.ui:63
msgid "Select a recording" msgid "Select a recording"
msgstr "" msgstr ""
#: ../res/ui/track_set_editor.ui:89 ../src/screens/recording.rs:30 #: ../res/ui/track_set_editor.ui:88 ../src/screens/recording.rs:30
msgid "Tracks" msgid "Tracks"
msgstr "" msgstr ""
@ -134,31 +134,31 @@ msgstr ""
msgid "Matching metadata" msgid "Matching metadata"
msgstr "" msgstr ""
#: ../res/ui/import_screen.ui:66 #: ../res/ui/import_screen.ui:64
msgid "Loading…" msgid "Loading…"
msgstr "" msgstr ""
#: ../res/ui/import_screen.ui:87 #: ../res/ui/import_screen.ui:88
msgid "Error while searching for matching metadata" msgid "Error while searching for matching metadata"
msgstr "" msgstr ""
#: ../res/ui/import_screen.ui:110 #: ../res/ui/import_screen.ui:114
msgid "No matching metadata found" msgid "No matching metadata found"
msgstr "" msgstr ""
#: ../res/ui/import_screen.ui:136 #: ../res/ui/import_screen.ui:144
msgid "Manually add metadata" msgid "Manually add metadata"
msgstr "" msgstr ""
#: ../res/ui/import_screen.ui:150 #: ../res/ui/import_screen.ui:156
msgid "Select existing medium" msgid "Select existing medium"
msgstr "" msgstr ""
#: ../res/ui/import_screen.ui:163 #: ../res/ui/import_screen.ui:169
msgid "Add a new medium" msgid "Add a new medium"
msgstr "" msgstr ""
#: ../res/ui/import_screen.ui:167 #: ../res/ui/import_screen.ui:173
msgid "Add" msgid "Add"
msgstr "" msgstr ""
@ -166,22 +166,22 @@ msgstr ""
msgid "Medium" msgid "Medium"
msgstr "" msgstr ""
#: ../res/ui/medium_editor.ui:75 #: ../res/ui/medium_editor.ui:73
msgid "Name of the medium" msgid "Name of the medium"
msgstr "" msgstr ""
#: ../res/ui/medium_editor.ui:99 #: ../res/ui/medium_editor.ui:98
msgid "Recordings" msgid "Recordings"
msgstr "" msgstr ""
#: ../res/ui/medium_editor.ui:201 ../res/ui/editor.ui:22 #: ../res/ui/medium_editor.ui:200 ../res/ui/editor.ui:22
#: ../src/import/source_selector.rs:50 ../src/screens/welcome.rs:55 #: ../src/import/source_selector.rs:50 ../src/screens/welcome.rs:55
#: ../src/preferences.rs:41 #: ../src/preferences.rs:43
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
#: ../res/ui/preferences.ui:11 ../src/editors/ensemble.rs:34 #: ../res/ui/preferences.ui:11 ../src/editors/ensemble.rs:35
#: ../src/editors/instrument.rs:34 ../src/editors/person.rs:38 #: ../src/editors/instrument.rs:35 ../src/editors/person.rs:39
msgid "General" msgid "General"
msgstr "" msgstr ""
@ -197,19 +197,41 @@ msgstr ""
msgid "None selected" msgid "None selected"
msgstr "" msgstr ""
#: ../res/ui/preferences.ui:34
msgid "Playlist"
msgstr ""
#: ../res/ui/preferences.ui:38
msgid "Keep playing"
msgstr ""
#: ../res/ui/preferences.ui:40
msgid "Whether to keep playing random tracks after the playlist ends."
msgstr ""
#: ../res/ui/preferences.ui:51
msgid "Choose full recordings"
msgstr ""
#: ../res/ui/preferences.ui:53
msgid ""
"Whether to choose full recordings instead of single tracks for random "
"playback."
msgstr ""
#: ../res/ui/recording_editor.ui:65 ../res/ui/work_editor.ui:65 #: ../res/ui/recording_editor.ui:65 ../res/ui/work_editor.ui:65
msgid "Overview" msgid "Overview"
msgstr "" msgstr ""
#: ../res/ui/recording_editor.ui:79 #: ../res/ui/recording_editor.ui:77
msgid "Select a work" msgid "Select a work"
msgstr "" msgstr ""
#: ../res/ui/recording_editor.ui:92 #: ../res/ui/recording_editor.ui:90
msgid "Comment" msgid "Comment"
msgstr "" msgstr ""
#: ../res/ui/recording_editor.ui:116 #: ../res/ui/recording_editor.ui:115
msgid "Performers" msgid "Performers"
msgstr "" msgstr ""
@ -217,20 +239,20 @@ msgstr ""
msgid "Search …" msgid "Search …"
msgstr "" msgstr ""
#: ../res/ui/work_editor.ui:18 ../res/ui/work_editor.ui:182 #: ../res/ui/work_editor.ui:18 ../res/ui/work_editor.ui:181
#: ../src/editors/recording.rs:173 #: ../src/editors/recording.rs:173
msgid "Work" msgid "Work"
msgstr "" msgstr ""
#: ../res/ui/work_editor.ui:79 #: ../res/ui/work_editor.ui:77
msgid "Select a composer" msgid "Select a composer"
msgstr "" msgstr ""
#: ../res/ui/work_editor.ui:116 #: ../res/ui/work_editor.ui:115
msgid "Instruments" msgid "Instruments"
msgstr "" msgstr ""
#: ../res/ui/work_editor.ui:143 #: ../res/ui/work_editor.ui:142
msgid "Structure" msgid "Structure"
msgstr "" msgstr ""
@ -264,43 +286,43 @@ msgstr ""
msgid "About Musicus" msgid "About Musicus"
msgstr "" msgstr ""
#: ../src/editors/performance.rs:42 #: ../src/editors/performance.rs:43
msgid "Performer" msgid "Performer"
msgstr "" msgstr ""
#: ../src/editors/performance.rs:44 #: ../src/editors/performance.rs:45
msgid "Select either a person or an ensemble as a performer." msgid "Select either a person or an ensemble as a performer."
msgstr "" msgstr ""
#: ../src/editors/performance.rs:62 #: ../src/editors/performance.rs:64
msgid "Role" msgid "Role"
msgstr "" msgstr ""
#: ../src/editors/performance.rs:64 #: ../src/editors/performance.rs:66
msgid "Optionally, choose a role to specify what the performer does." msgid "Optionally, choose a role to specify what the performer does."
msgstr "" msgstr ""
#: ../src/editors/ensemble.rs:31 ../src/editors/instrument.rs:31 #: ../src/editors/ensemble.rs:32 ../src/editors/instrument.rs:32
msgid "Name" msgid "Name"
msgstr "" msgstr ""
#: ../src/editors/ensemble.rs:65 #: ../src/editors/ensemble.rs:66
msgid "Failed to save ensemble!" msgid "Failed to save ensemble!"
msgstr "" msgstr ""
#: ../src/editors/instrument.rs:65 #: ../src/editors/instrument.rs:66
msgid "Failed to save instrument!" msgid "Failed to save instrument!"
msgstr "" msgstr ""
#: ../src/editors/person.rs:32 #: ../src/editors/person.rs:33
msgid "First name" msgid "First name"
msgstr "" msgstr ""
#: ../src/editors/person.rs:33 #: ../src/editors/person.rs:34
msgid "Last name" msgid "Last name"
msgstr "" msgstr ""
#: ../src/editors/person.rs:72 #: ../src/editors/person.rs:73
msgid "Failed to save person!" msgid "Failed to save person!"
msgstr "" msgstr ""
@ -308,8 +330,8 @@ msgstr ""
msgid "Composer" msgid "Composer"
msgstr "" msgstr ""
#: ../src/import/track_set_editor.rs:133 ../src/import/medium_preview.rs:171 #: ../src/import/track_set_editor.rs:133 ../src/import/medium_preview.rs:170
#: ../src/screens/medium.rs:74 ../src/screens/recording.rs:84 #: ../src/screens/medium.rs:72 ../src/screens/recording.rs:82
msgid "Unknown" msgid "Unknown"
msgstr "" msgstr ""
@ -337,11 +359,11 @@ msgstr ""
msgid "Delete person" msgid "Delete person"
msgstr "" msgstr ""
#: ../src/screens/recording.rs:55 #: ../src/screens/recording.rs:53
msgid "Edit recording" msgid "Edit recording"
msgstr "" msgstr ""
#: ../src/screens/recording.rs:65 #: ../src/screens/recording.rs:63
msgid "Delete recording" msgid "Delete recording"
msgstr "" msgstr ""
@ -352,7 +374,7 @@ msgid ""
"exists." "exists."
msgstr "" msgstr ""
#: ../src/screens/welcome.rs:51 ../src/preferences.rs:37 #: ../src/screens/welcome.rs:51 ../src/preferences.rs:39
msgid "Select music library folder" msgid "Select music library folder"
msgstr "" msgstr ""
@ -364,15 +386,15 @@ msgstr ""
msgid "Delete work" msgid "Delete work"
msgstr "" msgstr ""
#: ../src/screens/main.rs:196 #: ../src/screens/main.rs:200
msgid "Musicus" msgid "Musicus"
msgstr "" msgstr ""
#: ../src/screens/main.rs:198 #: ../src/screens/main.rs:202
msgid "The classical music player and organizer." msgid "The classical music player and organizer."
msgstr "" msgstr ""
#: ../src/screens/main.rs:200 #: ../src/screens/main.rs:204
msgid "Further information and source code" msgid "Further information and source code"
msgstr "" msgstr ""

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<requires lib="gtk" version="4.0"/> <requires lib="gtk" version="4.0" />
<requires lib="libadwaita" version="1.0"/> <requires lib="libadwaita" version="1.0" />
<object class="AdwPreferencesWindow" id="window"> <object class="AdwPreferencesWindow" id="window">
<property name="modal">True</property> <property name="modal">True</property>
<property name="default-width">400</property> <property name="default-width">400</property>
@ -29,6 +29,37 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Playlist</property>
<child>
<object class="AdwActionRow">
<property name="focusable">False</property>
<property name="title" translatable="yes">Keep playing</property>
<property name="activatable-widget">keep_playing_switch</property>
<property name="subtitle" translatable="yes">Whether to keep playing random tracks after the playlist ends.</property>
<child>
<object class="GtkSwitch" id="keep_playing_switch">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="focusable">False</property>
<property name="title" translatable="yes">Choose full recordings</property>
<property name="activatable-widget">play_full_recordings_switch</property>
<property name="subtitle" translatable="yes">Whether to choose full recordings instead of single tracks for random playback.</property>
<child>
<object class="GtkSwitch" id="play_full_recordings_switch">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>

View file

@ -21,6 +21,8 @@ impl Preferences {
get_widget!(builder, adw::Window, window); get_widget!(builder, adw::Window, window);
get_widget!(builder, adw::ActionRow, music_library_path_row); get_widget!(builder, adw::ActionRow, music_library_path_row);
get_widget!(builder, gtk::Button, select_music_library_path_button); get_widget!(builder, gtk::Button, select_music_library_path_button);
get_widget!(builder, gtk::Switch, keep_playing_switch);
get_widget!(builder, gtk::Switch, play_full_recordings_switch);
window.set_transient_for(Some(parent)); window.set_transient_for(Some(parent));
@ -48,7 +50,7 @@ impl Preferences {
if let gtk::ResponseType::Accept = response { if let gtk::ResponseType::Accept = response {
if let Some(file) = dialog.file() { if let Some(file) = dialog.file() {
if let Some(path) = file.path() { if let Some(path) = file.path() {
this.backend.set_music_library_path(path.clone()).unwrap(); Rc::clone(&this.backend).set_music_library_path(path.clone()).unwrap();
this.music_library_path_row.set_subtitle(path.to_str().unwrap()); this.music_library_path_row.set_subtitle(path.to_str().unwrap());
} }
} }
@ -60,6 +62,14 @@ impl Preferences {
dialog.show(); dialog.show();
})); }));
keep_playing_switch.connect_active_notify(clone!(@weak this => move |switch| {
Rc::clone(&this.backend).set_keep_playing(switch.is_active());
}));
play_full_recordings_switch.connect_active_notify(clone!(@weak this => move |switch| {
Rc::clone(&this.backend).set_play_full_recordings(switch.is_active());
}));
// Initialize // Initialize
if let Some(path) = this.backend.get_music_library_path() { if let Some(path) = this.backend.get_music_library_path() {
@ -67,6 +77,9 @@ impl Preferences {
.set_subtitle(path.to_str().unwrap()); .set_subtitle(path.to_str().unwrap());
} }
keep_playing_switch.set_active(this.backend.keep_playing());
play_full_recordings_switch.set_active(this.backend.play_full_recordings());
this this
} }

View file

@ -128,12 +128,16 @@ impl Screen<(), ()> for MainScreen {
search.is_empty() || title.contains(&search) search.is_empty() || title.contains(&search)
})); }));
this.handle.backend.pl().add_playlist_cb(clone!(@weak play_button_revealer => move |new_playlist| { this.handle.backend.pl().add_playlist_cb(
clone!(@weak play_button_revealer => move |new_playlist| {
play_button_revealer.set_reveal_child(new_playlist.is_empty()); play_button_revealer.set_reveal_child(new_playlist.is_empty());
})); }),
);
play_button.connect_clicked(clone!(@weak this => move |_| { play_button.connect_clicked(clone!(@weak this => move |_| {
this.handle.backend.pl().play_pause().unwrap(); if let Ok(recording) = this.handle.backend.db().random_recording() {
this.handle.backend.pl().add_items(this.handle.backend.db().get_tracks(&recording.id).unwrap()).unwrap();
}
})); }));
this.navigator.set_back_cb(clone!(@weak this => move || { this.navigator.set_back_cb(clone!(@weak this => move || {

View file

@ -55,9 +55,7 @@ impl Screen<Medium, ()> for MediumScreen {
section.add_action( section.add_action(
"media-playback-start-symbolic", "media-playback-start-symbolic",
clone!(@weak this => move || { clone!(@weak this => move || {
for track in &this.medium.tracks { this.handle.backend.pl().add_items(this.medium.tracks.clone()).unwrap();
this.handle.backend.pl().add_item(track.clone()).unwrap();
}
}), }),
); );

View file

@ -41,9 +41,7 @@ impl Screen<Recording, ()> for RecordingScreen {
section.add_action( section.add_action(
"media-playback-start-symbolic", "media-playback-start-symbolic",
clone!(@weak this => move || { clone!(@weak this => move || {
for track in &*this.tracks.borrow() { this.handle.backend.pl().add_items(this.tracks.borrow().clone()).unwrap();
this.handle.backend.pl().add_item(track.clone()).unwrap();
}
}), }),
); );

View file

@ -62,7 +62,7 @@ impl Screen<(), ()> for WelcomeScreen {
if let gtk::ResponseType::Accept = response { if let gtk::ResponseType::Accept = response {
if let Some(file) = dialog.file() { if let Some(file) = dialog.file() {
if let Some(path) = file.path() { if let Some(path) = file.path() {
this.handle.backend.set_music_library_path(path).unwrap(); Rc::clone(&this.handle.backend).set_music_library_path(path).unwrap();
} }
} }
} }

View file

@ -61,7 +61,7 @@ impl Window {
})); }));
// Initialize the backend. // Initialize the backend.
this.backend.init().unwrap(); Rc::clone(&this.backend).init().unwrap();
this this
} }