Update dependencies, adapt code, fix warnings

This commit is contained in:
Elias Projahn 2023-03-28 14:39:54 +02:00
parent 75d4e82cf8
commit 835d4f0d42
44 changed files with 595 additions and 541 deletions

View file

@ -6,10 +6,10 @@ edition = "2021"
[dependencies]
chrono = "0.4"
fragile = "2"
gio = "0.16"
glib = "0.16"
gstreamer = "0.19"
gstreamer-player = "0.19"
gio = "0.17"
glib = "0.17"
gstreamer = "0.20"
gstreamer-player = "0.20"
log = { version = "0.4", features = ["std"] }
musicus_database = { version = "0.1.0", path = "../database" }
musicus_import = { version = "0.1.0", path = "../import" }

View file

@ -1,6 +1,9 @@
use chrono::{Local, DateTime};
use chrono::{DateTime, Local};
use log::{Level, LevelFilter, Log, Metadata, Record};
use std::{fmt::Display, sync::{Arc, Mutex}};
use std::{
fmt::Display,
sync::{Arc, Mutex},
};
/// Register the custom logger. This will panic if called more than once.
pub fn register() -> Arc<Logger> {
@ -72,6 +75,10 @@ impl<'a> From<&Record<'a>> for LogMessage {
impl Display for LogMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {} ({}): {}", self.time, self.module, self.level, self.message)
write!(
f,
"{} {} ({}): {}",
self.time, self.module, self.level, self.message
)
}
}

View file

@ -1,6 +1,7 @@
use crate::{Backend, Error, Result};
use db::Track;
use glib::clone;
use gstreamer_player::PlayerVideoRenderer;
use musicus_database as db;
use std::cell::{Cell, RefCell};
use std::path::PathBuf;
@ -32,10 +33,7 @@ pub struct Player {
impl Player {
pub fn new(music_library_path: PathBuf) -> Rc<Self> {
let dispatcher = gstreamer_player::PlayerGMainContextSignalDispatcher::new(None);
let player = gstreamer_player::Player::new(
gstreamer_player::PlayerVideoRenderer::NONE,
Some(&dispatcher),
);
let player = gstreamer_player::Player::new(None::<PlayerVideoRenderer>, Some(dispatcher));
let mut config = player.config();
config.set_position_update_interval(250);
player.set_config(config).unwrap();

View file

@ -2,7 +2,7 @@ use chrono::Utc;
use diesel::prelude::*;
use log::info;
use crate::{Result, schema::ensembles, defer_foreign_keys};
use crate::{defer_foreign_keys, schema::ensembles, Result};
/// An ensemble that takes part in recordings.
#[derive(Insertable, Queryable, PartialEq, Eq, Hash, Debug, Clone)]

View file

@ -82,7 +82,7 @@ impl Track {
/// Table data for a [`Medium`].
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "mediums"]
#[diesel(table_name = mediums)]
struct MediumRow {
pub id: String,
pub name: String,
@ -93,7 +93,7 @@ struct MediumRow {
/// Table data for a [`Track`].
#[derive(Insertable, Queryable, QueryableByName, Debug, Clone)]
#[table_name = "tracks"]
#[diesel(table_name = tracks)]
struct TrackRow {
pub id: String,
pub medium: Option<String>,

View file

@ -97,7 +97,7 @@ impl PersonOrEnsemble {
/// Database table data for a recording.
#[derive(Insertable, Queryable, QueryableByName, Debug, Clone)]
#[table_name = "recordings"]
#[diesel(table_name = recordings)]
struct RecordingRow {
pub id: String,
pub work: String,
@ -120,7 +120,7 @@ impl From<Recording> for RecordingRow {
/// Database table data for a performance.
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "performances"]
#[diesel(table_name = performances)]
struct PerformanceRow {
pub id: i64,
pub recording: String,

View file

@ -10,7 +10,7 @@ use crate::{
/// Table row data for a work.
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "works"]
#[diesel(table_name = works)]
struct WorkRow {
pub id: String,
pub composer: String,
@ -33,7 +33,7 @@ impl From<Work> for WorkRow {
/// Definition that a work uses an instrument.
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "instrumentations"]
#[diesel(table_name = instrumentations)]
struct InstrumentationRow {
pub id: i64,
pub work: String,
@ -42,7 +42,7 @@ struct InstrumentationRow {
/// Table row data for a work part.
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "work_parts"]
#[diesel(table_name = work_parts)]
struct WorkPartRow {
pub id: i64,
pub work: String,

View file

@ -4,10 +4,10 @@ version = "0.1.0"
edition = "2021"
[dependencies]
base64 = "0.13"
glib = "0.16"
gstreamer = "0.19"
gstreamer-pbutils = "0.19"
base64 = "0.21"
glib = "0.17"
gstreamer = "0.20"
gstreamer-pbutils = "0.20"
log = "0.4"
once_cell = "1"
rand = "0.8"

View file

@ -1,5 +1,6 @@
use crate::error::{Error, Result};
use crate::session::{ImportSession, ImportTrack, State};
use base64::Engine;
use gstreamer::prelude::*;
use gstreamer::tags::{Duration, TrackNumber};
use gstreamer::{ClockTime, ElementFactory, MessageType, MessageView, TocEntryType};
@ -108,7 +109,7 @@ pub(super) fn new() -> Result<ImportSession> {
}
}
let source_id = base64::encode_config(hasher.finalize(), base64::URL_SAFE);
let source_id = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(hasher.finalize());
info!("Successfully loaded audio CD with {} tracks.", tracks.len());
info!("Source ID: {}", source_id);

View file

@ -1,5 +1,6 @@
use crate::error::{Error, Result};
use crate::session::{ImportSession, ImportTrack, State};
use base64::Engine;
use gstreamer::ClockTime;
use gstreamer_pbutils::Discoverer;
use log::{info, warn};
@ -64,7 +65,7 @@ pub(super) fn new(path: PathBuf) -> Result<ImportSession> {
}
}
let source_id = base64::encode_config(hasher.finalize(), base64::URL_SAFE);
let source_id = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(hasher.finalize());
info!("Source ID: {}", source_id);

View file

@ -5,13 +5,13 @@ edition = "2021"
[dependencies]
anyhow = "1"
adw = { package = "libadwaita", version = "0.2", features = ["v1_2"] }
adw = { package = "libadwaita", version = "0.3", features = ["v1_2"] }
futures-channel = "0.3"
gettext-rs = { version = "0.7", features = ["gettext-system"] }
gio = "0.16"
glib = "0.16"
gstreamer = "0.19"
gtk = { package = "gtk4", version = "0.5" }
gio = "0.17"
glib = "0.17"
gstreamer = "0.20"
gtk = { package = "gtk4", version = "0.6" }
gtk-macros = "0.3"
log = "0.4"
musicus_backend = { version = "0.1.0", path = "../backend" }

View file

@ -2,8 +2,8 @@ use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::{Editor, Section, Widget};
use anyhow::Result;
use gettextrs::gettext;
use gtk::{builders::ListBoxBuilder, glib::clone, prelude::*};
use musicus_backend::db::{generate_id, Ensemble, self};
use gtk::{glib::clone, prelude::*};
use musicus_backend::db::{self, generate_id, Ensemble};
use std::rc::Rc;
/// A dialog for creating or editing a ensemble.
@ -23,12 +23,12 @@ impl Screen<Option<Ensemble>, Ensemble> for EnsembleEditor {
let editor = Editor::new();
editor.set_title("Ensemble");
let list = ListBoxBuilder::new()
let list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
let name = adw::EntryRow::builder().title(&gettext("Name")).build();
let name = adw::EntryRow::builder().title(gettext("Name")).build();
list.append(&name);
let section = Section::new(&gettext("General"), &list);
@ -88,7 +88,10 @@ impl EnsembleEditor {
let ensemble = Ensemble::new(self.id.clone(), name.to_string());
db::update_ensemble(&mut self.handle.backend.db().lock().unwrap(), ensemble.clone())?;
db::update_ensemble(
&mut self.handle.backend.db().lock().unwrap(),
ensemble.clone(),
)?;
self.handle.backend.library_changed();
Ok(ensemble)

View file

@ -2,7 +2,7 @@ use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::{Editor, Section, Widget};
use anyhow::Result;
use gettextrs::gettext;
use gtk::{builders::ListBoxBuilder, glib::clone, prelude::*};
use gtk::{glib::clone, prelude::*};
use musicus_backend::db::{self, generate_id, Instrument};
use std::rc::Rc;
@ -23,12 +23,12 @@ impl Screen<Option<Instrument>, Instrument> for InstrumentEditor {
let editor = Editor::new();
editor.set_title("Instrument/Role");
let list = ListBoxBuilder::new()
let list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
let name = adw::EntryRow::builder().title(&gettext("Name")).build();
let name = adw::EntryRow::builder().title(gettext("Name")).build();
list.append(&name);
let section = Section::new(&gettext("General"), &list);

View file

@ -3,8 +3,8 @@ use crate::selectors::{EnsembleSelector, InstrumentSelector, PersonSelector};
use crate::widgets::{ButtonRow, Editor, Section, Widget};
use adw::prelude::*;
use gettextrs::gettext;
use gtk::builders::ButtonBuilder;
use gtk::{builders::ListBoxBuilder, glib::clone};
use gtk::glib::clone;
use log::error;
use musicus_backend::db::{Ensemble, Instrument, Performance, Person, PersonOrEnsemble};
use std::cell::RefCell;
@ -30,7 +30,7 @@ impl Screen<Option<Performance>, Performance> for PerformanceEditor {
editor.set_title("Performance");
editor.set_may_save(false);
let performer_list = ListBoxBuilder::new()
let performer_list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
@ -46,12 +46,12 @@ impl Screen<Option<Performance>, Performance> for PerformanceEditor {
"Select either a person or an ensemble as a performer.",
));
let role_list = ListBoxBuilder::new()
let role_list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
let reset_role_button = ButtonBuilder::new()
let reset_role_button = gtk::Button::builder()
.icon_name("user-trash-symbolic")
.valign(gtk::Align::Center)
.visible(false)

View file

@ -3,8 +3,8 @@ use crate::widgets::{Editor, Section, Widget};
use anyhow::Result;
use gettextrs::gettext;
use glib::clone;
use gtk::{builders::ListBoxBuilder, prelude::*};
use musicus_backend::db::{generate_id, Person, self};
use gtk::prelude::*;
use musicus_backend::db::{self, generate_id, Person};
use std::rc::Rc;
/// A dialog for creating or editing a person.
@ -25,18 +25,16 @@ impl Screen<Option<Person>, Person> for PersonEditor {
let editor = Editor::new();
editor.set_title("Person");
let list = ListBoxBuilder::new()
let list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
let first_name = adw::EntryRow::builder()
.title(&gettext("First name"))
.title(gettext("First name"))
.build();
let last_name = adw::EntryRow::builder()
.title(&gettext("Last name"))
.build();
let last_name = adw::EntryRow::builder().title(gettext("Last name")).build();
list.append(&first_name);
list.append(&last_name);

View file

@ -2,7 +2,7 @@ use super::performance::PerformanceEditor;
use crate::navigator::{NavigationHandle, Screen};
use crate::selectors::WorkSelector;
use crate::widgets::{List, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use anyhow::Result;
use gettextrs::gettext;
@ -129,10 +129,10 @@ impl Screen<Option<Recording>, Recording> for RecordingEditor {
});
}));
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.focusable(false)
.activatable_widget(&edit_button)
.title(&performance.get_title())
.title(performance.get_title())
.build();
row.add_suffix(&delete_button);

View file

@ -2,7 +2,7 @@ use super::work_part::WorkPartEditor;
use crate::navigator::{NavigationHandle, Screen};
use crate::selectors::{InstrumentSelector, PersonSelector};
use crate::widgets::{List, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use anyhow::Result;
use gettextrs::gettext;
@ -125,7 +125,7 @@ impl Screen<Option<Work>, Work> for WorkEditor {
this.instrument_list.update(length);
}));
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.title(&instrument.name)
.build();
@ -184,7 +184,7 @@ impl Screen<Option<Work>, Work> for WorkEditor {
});
}));
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.focusable(false)
.title(&part.title)
.activatable_widget(&edit_button)

View file

@ -3,7 +3,7 @@ use super::medium_preview::MediumPreview;
use crate::navigator::{NavigationHandle, Screen};
use crate::selectors::MediumSelector;
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use glib::clone;
use gtk_macros::get_widget;
@ -68,10 +68,10 @@ impl ImportScreen {
let this = self;
for medium in mediums {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&medium.name)
.subtitle(&format!("{} Tracks", medium.tracks.len()))
.subtitle(format!("{} Tracks", medium.tracks.len()))
.build();
row.connect_activated(clone!(@weak this => move |_| {

View file

@ -1,7 +1,7 @@
use super::track_set_editor::{TrackData, TrackSetData, TrackSetEditor};
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::{List, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use anyhow::Result;
use glib::clone;
@ -109,10 +109,10 @@ impl Screen<(Arc<ImportSession>, Option<Medium>), Medium> for MediumEditor {
edit_button.set_valign(gtk::Align::Center);
edit_button.set_child(Some(&edit_image));
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.focusable(false)
.title(&title)
.subtitle(&subtitle)
.title(title)
.subtitle(subtitle)
.activatable_widget(&edit_button)
.build();

View file

@ -1,11 +1,11 @@
use super::medium_editor::MediumEditor;
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use anyhow::{anyhow, Result};
use gettextrs::gettext;
use glib::clone;
use gtk::builders::{FrameBuilder, ListBoxBuilder};
use gtk::prelude::*;
use gtk_macros::get_widget;
use musicus_backend::db::{self, Medium};
@ -141,16 +141,16 @@ impl MediumPreview {
if track.recording.id != last_recording_id {
last_recording_id = &track.recording.id;
let list = ListBoxBuilder::new()
let list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.margin_bottom(12)
.css_classes(vec![String::from("boxed-list")])
.build();
let header = ActionRowBuilder::new()
let header = adw::ActionRow::builder()
.activatable(false)
.title(&track.recording.work.get_title())
.subtitle(&track.recording.get_performers())
.title(track.recording.work.get_title())
.subtitle(track.recording.get_performers())
.build();
list.append(&header);
@ -174,9 +174,9 @@ impl MediumPreview {
parts.join(", ")
};
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(false)
.title(&title)
.title(title)
.subtitle(&import_tracks[track.source_index].name)
.margin_start(12)
.build();
@ -186,7 +186,7 @@ impl MediumPreview {
}
if let Some(list) = &last_list {
let frame = FrameBuilder::new().margin_bottom(12).build();
let frame = gtk::Frame::builder().margin_bottom(12).build();
frame.set_child(Some(list));
self.medium_box.append(&frame);

View file

@ -1,9 +1,9 @@
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use glib::clone;
use gtk::builders::ListBoxBuilder;
use gtk_macros::get_widget;
use musicus_backend::db::Recording;
use std::cell::RefCell;
@ -31,7 +31,7 @@ impl Screen<(Recording, Vec<usize>), Vec<usize>> for TrackEditor {
get_widget!(builder, gtk::Button, select_button);
get_widget!(builder, adw::Clamp, clamp);
let parts_list = ListBoxBuilder::new()
let parts_list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
@ -68,7 +68,7 @@ impl Screen<(Recording, Vec<usize>), Vec<usize>> for TrackEditor {
}
}));
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.focusable(false)
.title(&part.title)
.activatable_widget(&check)

View file

@ -1,9 +1,9 @@
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use glib::clone;
use gtk::builders::ListBoxBuilder;
use gtk_macros::get_widget;
use musicus_backend::import::ImportSession;
use std::cell::RefCell;
@ -31,7 +31,7 @@ impl Screen<Arc<ImportSession>, Vec<usize>> for TrackSelector {
get_widget!(builder, gtk::Button, select_button);
get_widget!(builder, adw::Clamp, clamp);
let track_list = ListBoxBuilder::new()
let track_list = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
@ -78,7 +78,7 @@ impl Screen<Arc<ImportSession>, Vec<usize>> for TrackSelector {
}
}));
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.focusable(false)
.title(&track.name)
.activatable_widget(&check)

View file

@ -3,7 +3,7 @@ use super::track_selector::TrackSelector;
use crate::navigator::{NavigationHandle, Screen};
use crate::selectors::RecordingSelector;
use crate::widgets::{List, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -145,9 +145,9 @@ impl Screen<Arc<ImportSession>, TrackSetData> for TrackSetEditor {
edit_button.set_valign(gtk::Align::Center);
edit_button.set_child(Some(&edit_image));
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.focusable(false)
.title(&title)
.title(title)
.subtitle(track_name)
.activatable_widget(&edit_button)
.build();

View file

@ -2,7 +2,7 @@ use crate::widgets::Widget;
use futures_channel::oneshot;
use futures_channel::oneshot::{Receiver, Sender};
use glib::clone;
use gtk::builders::StackBuilder;
use gtk::prelude::*;
use musicus_backend::Backend;
use std::cell::{Cell, RefCell};
@ -97,7 +97,7 @@ impl Navigator {
W: IsA<gtk::Window>,
E: IsA<gtk::Widget>,
{
let widget = StackBuilder::new()
let widget = gtk::Stack::builder()
.hhomogeneous(false)
.vhomogeneous(false)
.interpolate_size(true)

View file

@ -3,7 +3,7 @@ use crate::editors::EnsembleEditor;
use crate::navigator::{NavigationHandle, NavigatorWindow, Screen};
use crate::widgets;
use crate::widgets::{List, Section, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -75,10 +75,10 @@ impl Screen<Ensemble, ()> for EnsembleScreen {
clone!(@weak this => @default-panic, move |index| {
let recording = &this.recordings.borrow()[index];
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&recording.work.get_title())
.subtitle(&recording.get_performers())
.title(recording.work.get_title())
.subtitle(recording.get_performers())
.build();
let recording = recording.to_owned();
@ -105,7 +105,7 @@ impl Screen<Ensemble, ()> for EnsembleScreen {
.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
let medium = &this.mediums.borrow()[index];
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&medium.name)
.build();

View file

@ -4,7 +4,7 @@ use crate::import::SourceSelector;
use crate::navigator::{NavigationHandle, Navigator, NavigatorWindow, Screen};
use crate::preferences::Preferences;
use crate::widgets::{List, PlayerBar, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -102,9 +102,9 @@ impl Screen<(), ()> for MainScreen {
.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
let poe = &this.poes.borrow()[index];
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&poe.get_title())
.title(poe.get_title())
.build();
let poe = poe.to_owned();
@ -207,13 +207,13 @@ impl MainScreen {
copy_button.connect_clicked(clone!(@weak logger, @weak toast_overlay => move |widget| {
widget.clipboard().set_text(&logger.messages().into_iter().map(|m| m.to_string()).collect::<Vec<String>>().join("\n"));
toast_overlay.add_toast(&adw::Toast::builder().title(&gettext("Copied to clipboard")).build());
toast_overlay.add_toast(adw::Toast::builder().title(gettext("Copied to clipboard")).build());
}));
let header = adw::HeaderBar::builder()
.title_widget(
&adw::WindowTitle::builder()
.title(&gettext("Debug log"))
.title(gettext("Debug log"))
.build(),
)
.build();
@ -227,7 +227,7 @@ impl MainScreen {
for message in logger.messages() {
log_list.append(
&adw::ActionRow::builder()
.title(&format!(
.title(format!(
"<b>{}</b> {} <i>{}</i>",
message.level,
message.time.format("%Y-%m-%d %H:%M:%S"),
@ -255,7 +255,7 @@ impl MainScreen {
adw::Window::builder()
.transient_for(&self.handle.window)
.modal(true)
.title(&gettext("Debug log"))
.title(gettext("Debug log"))
.default_width(640)
.default_height(480)
.content(&toast_overlay)
@ -269,10 +269,10 @@ impl MainScreen {
.transient_for(&self.handle.window)
.modal(true)
.application_icon("de.johrpan.musicus")
.application_name(&gettext("Musicus"))
.application_name(gettext("Musicus"))
.developer_name("Elias Projahn")
.version(config::VERSION)
.comments(&gettext("The classical music player and organizer."))
.comments(gettext("The classical music player and organizer."))
.website("https://code.johrpan.de/johrpan/musicus")
.developers(vec![String::from("Elias Projahn <elias@johrpan.de>")])
.copyright("© 2022 Elias Projahn")

View file

@ -1,7 +1,7 @@
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets;
use crate::widgets::{List, Section, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -75,10 +75,10 @@ impl Screen<Medium, ()> for MediumScreen {
parts.join(", ")
};
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.margin_start(12)
.selectable(false)
.title(&title)
.title(title)
.build();
row.upcast()

View file

@ -3,7 +3,7 @@ use crate::editors::PersonEditor;
use crate::navigator::{NavigationHandle, NavigatorWindow, Screen};
use crate::widgets;
use crate::widgets::{List, Section, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -81,7 +81,7 @@ impl Screen<Person, ()> for PersonScreen {
.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
let work = &this.works.borrow()[index];
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&work.title)
.build();
@ -109,10 +109,10 @@ impl Screen<Person, ()> for PersonScreen {
clone!(@weak this => @default-panic, move |index| {
let recording = &this.recordings.borrow()[index];
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&recording.work.get_title())
.subtitle(&recording.get_performers())
.title(recording.work.get_title())
.subtitle(recording.get_performers())
.build();
let recording = recording.to_owned();
@ -139,7 +139,7 @@ impl Screen<Person, ()> for PersonScreen {
.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
let medium = &this.mediums.borrow()[index];
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&medium.name)
.build();

View file

@ -65,7 +65,7 @@ impl Screen<(), ()> for PlayerScreen {
content.append(&list.widget);
let event_controller = gtk::EventControllerLegacy::new();
position_scale.add_controller(&event_controller);
position_scale.add_controller(event_controller.clone());
let this = Rc::new(Self {
handle,

View file

@ -2,7 +2,7 @@ use crate::editors::RecordingEditor;
use crate::navigator::{NavigationHandle, NavigatorWindow, Screen};
use crate::widgets;
use crate::widgets::{List, Section, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -85,8 +85,8 @@ impl Screen<Recording, ()> for RecordingScreen {
title_parts.join(", ")
};
let row = ActionRowBuilder::new()
.title(&title)
let row = adw::ActionRow::builder()
.title(title)
.build();
row.upcast()

View file

@ -1,9 +1,7 @@
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::{HeaderBarBuilder, StatusPageBuilder};
use gettextrs::gettext;
use glib::clone;
use gtk::builders::{BoxBuilder, ButtonBuilder};
use gtk::prelude::*;
use std::rc::Rc;
@ -17,23 +15,23 @@ pub struct WelcomeScreen {
impl Screen<(), ()> for WelcomeScreen {
fn new(_: (), handle: NavigationHandle<()>) -> Rc<Self> {
let widget = BoxBuilder::new()
let widget = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.build();
let header = HeaderBarBuilder::new()
let header = gtk::HeaderBar::builder()
.title_widget(&adw::WindowTitle::new("Musicus", ""))
.build();
let button = ButtonBuilder::new()
let button = gtk::Button::builder()
.halign(gtk::Align::Center)
.label(&gettext("Select folder"))
.label(gettext("Select folder"))
.build();
let welcome = StatusPageBuilder::new()
let welcome = adw::StatusPage::builder()
.icon_name("folder-music-symbolic")
.title(&gettext("Welcome to Musicus!"))
.description(&gettext(
.title(gettext("Welcome to Musicus!"))
.description(gettext(
"Get startet by selecting the folder containing your music \
files! Musicus will create a new database there or open one that already exists.",
))

View file

@ -3,7 +3,7 @@ use crate::editors::WorkEditor;
use crate::navigator::{NavigationHandle, NavigatorWindow, Screen};
use crate::widgets;
use crate::widgets::{List, Section, Widget};
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -70,10 +70,10 @@ impl Screen<Work, ()> for WorkScreen {
clone!(@weak this => @default-panic, move |index| {
let recording = &this.recordings.borrow()[index];
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&recording.work.get_title())
.subtitle(&recording.get_performers())
.title(recording.work.get_title())
.subtitle(recording.get_performers())
.build();
let recording = recording.to_owned();

View file

@ -2,12 +2,12 @@ use super::selector::Selector;
use crate::editors::EnsembleEditor;
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use log::warn;
use musicus_backend::db::{Ensemble, self};
use musicus_backend::db::{self, Ensemble};
use std::rc::Rc;
/// A screen for selecting a ensemble.
@ -42,7 +42,7 @@ impl Screen<(), Ensemble> for EnsembleSelector {
this.selector
.set_make_widget(clone!(@weak this => @default-panic, move |ensemble| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&ensemble.name)
.build();
@ -63,8 +63,9 @@ impl Screen<(), Ensemble> for EnsembleSelector {
this.selector
.set_filter(|search, ensemble| ensemble.name.to_lowercase().contains(search));
this.selector
.set_items(db::get_recent_ensembles(&mut this.handle.backend.db().lock().unwrap(), ).unwrap());
this.selector.set_items(
db::get_recent_ensembles(&mut this.handle.backend.db().lock().unwrap()).unwrap(),
);
this
}

View file

@ -2,12 +2,12 @@ use super::selector::Selector;
use crate::editors::InstrumentEditor;
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use log::warn;
use musicus_backend::db::{Instrument, self};
use musicus_backend::db::{self, Instrument};
use std::rc::Rc;
/// A screen for selecting a instrument.
@ -42,7 +42,7 @@ impl Screen<(), Instrument> for InstrumentSelector {
this.selector
.set_make_widget(clone!(@weak this => @default-panic, move |instrument| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&instrument.name)
.build();
@ -63,8 +63,9 @@ impl Screen<(), Instrument> for InstrumentSelector {
this.selector
.set_filter(|search, instrument| instrument.name.to_lowercase().contains(search));
this.selector
.set_items(db::get_recent_instruments(&mut this.handle.backend.db().lock().unwrap(), ).unwrap());
this.selector.set_items(
db::get_recent_instruments(&mut this.handle.backend.db().lock().unwrap()).unwrap(),
);
this
}

View file

@ -1,7 +1,7 @@
use super::selector::Selector;
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -31,9 +31,9 @@ impl Screen<(), Medium> for MediumSelector {
}));
this.selector.set_make_widget(clone!(@weak this => @default-panic, move |poe| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&poe.get_title())
.title(poe.get_title())
.build();
let poe = poe.to_owned();
@ -106,7 +106,7 @@ impl Screen<PersonOrEnsemble, Medium> for MediumSelectorMediumScreen {
this.selector
.set_make_widget(clone!(@weak this => @default-panic, move |medium| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&medium.name)
.build();

View file

@ -2,12 +2,12 @@ use super::selector::Selector;
use crate::editors::PersonEditor;
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use log::warn;
use musicus_backend::db::{Person, self};
use musicus_backend::db::{self, Person};
use std::rc::Rc;
/// A screen for selecting a person.
@ -42,9 +42,9 @@ impl Screen<(), Person> for PersonSelector {
this.selector
.set_make_widget(clone!(@weak this => @default-panic, move |person| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&person.name_lf())
.title(person.name_lf())
.build();
let person = person.to_owned();
@ -63,8 +63,9 @@ impl Screen<(), Person> for PersonSelector {
this.selector
.set_filter(|search, person| person.name_fl().to_lowercase().contains(search));
this.selector
.set_items(db::get_recent_persons(&mut this.handle.backend.db().lock().unwrap(), ).unwrap());
this.selector.set_items(
db::get_recent_persons(&mut this.handle.backend.db().lock().unwrap()).unwrap(),
);
this
}

View file

@ -2,7 +2,7 @@ use super::selector::Selector;
use crate::editors::{PersonEditor, RecordingEditor, WorkEditor};
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
@ -53,9 +53,9 @@ impl Screen<(), Recording> for RecordingSelector {
}));
this.selector.set_make_widget(clone!(@weak this => @default-panic, move |person| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&person.name_lf())
.title(person.name_lf())
.build();
let person = person.to_owned();
@ -129,7 +129,7 @@ impl Screen<Person, Work> for RecordingSelectorWorkScreen {
this.selector
.set_make_widget(clone!(@weak this => @default-panic, move |work| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&work.title)
.build();
@ -197,9 +197,9 @@ impl Screen<Work, Recording> for RecordingSelectorRecordingScreen {
this.selector
.set_make_widget(clone!(@weak this => @default-panic, move |recording| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&recording.get_performers())
.title(recording.get_performers())
.build();
let recording = recording.to_owned();

View file

@ -2,12 +2,12 @@ use super::selector::Selector;
use crate::editors::{PersonEditor, WorkEditor};
use crate::navigator::{NavigationHandle, Screen};
use crate::widgets::Widget;
use adw::builders::ActionRowBuilder;
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use log::warn;
use musicus_backend::db::{Person, Work, self};
use musicus_backend::db::{self, Person, Work};
use std::rc::Rc;
/// A screen for selecting a work.
@ -47,9 +47,9 @@ impl Screen<(), Work> for WorkSelector {
}));
this.selector.set_make_widget(clone!(@weak this => @default-panic, move |person| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&person.name_lf())
.title(person.name_lf())
.build();
let person = person.to_owned();
@ -71,8 +71,9 @@ impl Screen<(), Work> for WorkSelector {
this.selector
.set_filter(|search, person| person.name_fl().to_lowercase().contains(search));
this.selector
.set_items(db::get_recent_persons(&mut this.handle.backend.db().lock().unwrap()).unwrap());
this.selector.set_items(
db::get_recent_persons(&mut this.handle.backend.db().lock().unwrap()).unwrap(),
);
this
}
@ -118,7 +119,7 @@ impl Screen<Person, Work> for WorkSelectorWorkScreen {
this.selector
.set_make_widget(clone!(@weak this => @default-panic, move |work| {
let row = ActionRowBuilder::new()
let row = adw::ActionRow::builder()
.activatable(true)
.title(&work.title)
.build();
@ -138,8 +139,13 @@ impl Screen<Person, Work> for WorkSelectorWorkScreen {
this.selector
.set_filter(|search, work| work.title.to_lowercase().contains(search));
this.selector
.set_items(db::get_works(&mut this.handle.backend.db().lock().unwrap(), &this.person.id).unwrap());
this.selector.set_items(
db::get_works(
&mut this.handle.backend.db().lock().unwrap(),
&this.person.id,
)
.unwrap(),
);
this
}

View file

@ -1,6 +1,5 @@
use super::Widget;
use adw::{builders::ActionRowBuilder, prelude::*};
use gtk::builders::ButtonBuilder;
use adw::prelude::*;
/// A list box row with a single button.
pub struct ButtonRow {
@ -14,12 +13,12 @@ pub struct ButtonRow {
impl ButtonRow {
/// Create a new button row.
pub fn new(title: &str, label: &str) -> Self {
let button = ButtonBuilder::new()
let button = gtk::Button::builder()
.valign(gtk::Align::Center)
.label(label)
.build();
let widget = ActionRowBuilder::new()
let widget = adw::ActionRow::builder()
.focusable(false)
.activatable_widget(&button)
.title(title)

View file

@ -1,6 +1,6 @@
use gio::prelude::*;
use gio::subclass::prelude::*;
use once_cell::sync::Lazy;
use std::cell::Cell;
glib::wrapper! {
@ -12,24 +12,28 @@ glib::wrapper! {
impl IndexedListModel {
/// Set the length of the list model.
pub fn set_length(&self, length: u32) {
let old_length = self.property("length");
self.set_property("length", &length);
let old_length = self.n_items();
self.set_n_items(length);
self.items_changed(0, old_length, length);
}
}
impl Default for IndexedListModel {
fn default() -> Self {
glib::Object::new(&[])
glib::Object::new()
}
}
mod indexed_list_model_imp {
use glib::Properties;
use super::*;
#[derive(Debug, Default)]
#[derive(Properties, Default)]
#[properties(wrapper_type = super::IndexedListModel)]
pub struct IndexedListModel {
length: Cell<u32>,
#[property(get, set)]
n_items: Cell<u32>,
}
#[glib::object_subclass]
@ -42,36 +46,15 @@ mod indexed_list_model_imp {
impl ObjectImpl for IndexedListModel {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecUInt::new(
"length",
"Length",
"Length",
0,
std::u32::MAX,
0,
glib::ParamFlags::READWRITE,
)]
});
PROPERTIES.as_ref()
Self::derived_properties()
}
fn set_property(&self, _: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"length" => {
let length = value.get::<u32>().unwrap();
self.length.set(length);
}
_ => unimplemented!(),
}
fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
self.derived_set_property(id, value, pspec)
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"length" => self.length.get().to_value(),
_ => unimplemented!(),
}
fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
self.derived_property(id, pspec)
}
}
@ -81,7 +64,7 @@ mod indexed_list_model_imp {
}
fn n_items(&self) -> u32 {
self.length.get()
self.n_items.get()
}
fn item(&self, position: u32) -> Option<glib::Object> {
@ -98,7 +81,9 @@ glib::wrapper! {
impl ItemIndex {
/// Create a new item index.
pub fn new(value: u32) -> Self {
glib::Object::new(&[("value", &value)])
let object = glib::Object::new::<Self>();
object.set_value(value);
object
}
/// Get the value of the item index..
@ -108,10 +93,14 @@ impl ItemIndex {
}
mod item_index_imp {
use glib::Properties;
use super::*;
#[derive(Debug, Default)]
#[derive(Properties, Default)]
#[properties(wrapper_type = super::ItemIndex)]
pub struct ItemIndex {
#[property(get, set)]
value: Cell<u32>,
}
@ -125,36 +114,15 @@ mod item_index_imp {
impl ObjectImpl for ItemIndex {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecUInt::new(
"value",
"Value",
"Value",
0,
std::u32::MAX,
0,
glib::ParamFlags::READWRITE,
)]
});
PROPERTIES.as_ref()
Self::derived_properties()
}
fn set_property(&self, _: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"value" => {
let value = value.get::<u32>().unwrap();
self.value.set(value);
}
_ => unimplemented!(),
}
fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
self.derived_set_property(id, value, pspec)
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"value" => self.value.get().to_value(),
_ => unimplemented!(),
}
fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
self.derived_property(id, pspec)
}
}
}

View file

@ -1,6 +1,6 @@
use super::indexed_list_model::{IndexedListModel, ItemIndex};
use glib::clone;
use gtk::{builders::ListBoxBuilder, gdk, prelude::*};
use gtk::{gdk, prelude::*};
use std::cell::{Cell, RefCell};
use std::rc::Rc;
@ -20,14 +20,14 @@ impl List {
pub fn new() -> Rc<Self> {
let model = IndexedListModel::default();
let filter = gtk::CustomFilter::new(|_| true);
let filter_model = gtk::FilterListModel::new(Some(&model), Some(&filter));
let filter_model = gtk::FilterListModel::new(Some(model.clone()), Some(filter.clone()));
// TODO: Switch to gtk::ListView.
// let selection = gtk::NoSelection::new(Some(&model));
// let factory = gtk::SignalListItemFactory::new();
// let widget = gtk::ListView::new(Some(&selection), Some(&factory));
let widget = ListBoxBuilder::new()
let widget = gtk::ListBox::builder()
.selection_mode(gtk::SelectionMode::None)
.css_classes(vec![String::from("boxed-list")])
.build();
@ -45,7 +45,7 @@ impl List {
this.filter
.set_filter_func(clone!(@strong this => move |index| {
if let Some(cb) = &*this.filter_cb.borrow() {
let index = index.downcast_ref::<ItemIndex>().unwrap().get() as usize;
let index = index.downcast_ref::<ItemIndex>().unwrap().value() as usize;
cb(index)
} else {
true
@ -81,8 +81,8 @@ impl List {
}
}));
widget.add_controller(&drag_source);
widget.add_controller(&drop_target);
widget.add_controller(drag_source);
widget.add_controller(drop_target);
}
widget
@ -109,6 +109,7 @@ impl List {
/// false, the item will not be shown.
pub fn set_filter_cb<F: Fn(usize) -> bool + 'static>(&self, cb: F) {
self.filter_cb.replace(Some(Box::new(cb)));
self.invalidate_filter();
}
/// Set the closure to be called to when the use has dragged an item to a

View file

@ -1,5 +1,5 @@
use super::Widget;
use gtk::{builders::ButtonBuilder, prelude::*};
use gtk::prelude::*;
use gtk_macros::get_widget;
/// A widget displaying a title, a framed child widget and, if needed, some
@ -46,7 +46,7 @@ impl Section {
/// situations where the widget is visible. The new button will be packed
/// to the end of the title box.
pub fn add_action<F: Fn() + 'static>(&self, icon_name: &str, cb: F) {
let button = ButtonBuilder::new()
let button = gtk::Button::builder()
.has_frame(false)
.valign(gtk::Align::Center)
.margin_top(12)

View file

@ -1,9 +1,9 @@
use crate::navigator::Navigator;
use crate::screens::{MainScreen, WelcomeScreen};
use adw::builders::HeaderBarBuilder;
use adw::prelude::*;
use glib::clone;
use gtk::builders::{BoxBuilder, SpinnerBuilder};
use musicus_backend::{Backend, BackendState};
use std::rc::Rc;
@ -23,15 +23,15 @@ impl Window {
window.set_title(Some("Musicus"));
window.set_default_size(1000, 707);
let loading_screen = BoxBuilder::new()
let loading_screen = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.build();
let header = HeaderBarBuilder::new()
let header = gtk::HeaderBar::builder()
.title_widget(&adw::WindowTitle::new("Musicus", ""))
.build();
let spinner = SpinnerBuilder::new()
let spinner = gtk::Spinner::builder()
.hexpand(true)
.vexpand(true)
.halign(gtk::Align::Center)