mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
database: Store access times
This commit is contained in:
parent
5c64bdef7e
commit
a0554a478f
20 changed files with 315 additions and 104 deletions
31
Cargo.lock
generated
31
Cargo.lock
generated
|
|
@ -121,6 +121,19 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.2"
|
||||
|
|
@ -353,7 +366,7 @@ checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1016,6 +1029,7 @@ dependencies = [
|
|||
name = "musicus_database"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"diesel",
|
||||
"diesel_migrations",
|
||||
"log",
|
||||
|
|
@ -1481,6 +1495,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.17.0"
|
||||
|
|
@ -1564,9 +1589,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
diesel = { version = "1.4.5", features = ["sqlite"] }
|
||||
diesel_migrations = "1.4.0"
|
||||
chrono = "0.4.19"
|
||||
log = "0.4.14"
|
||||
rand = "0.7.3"
|
||||
thiserror = "1.0.23"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
ALTER TABLE "persons" DROP COLUMN "last_used";
|
||||
ALTER TABLE "persons" DROP COLUMN "last_played";
|
||||
|
||||
ALTER TABLE "instruments" DROP COLUMN "last_used";
|
||||
ALTER TABLE "instruments" DROP COLUMN "last_played";
|
||||
|
||||
ALTER TABLE "works" DROP COLUMN "last_used";
|
||||
ALTER TABLE "works" DROP COLUMN "last_played";
|
||||
|
||||
ALTER TABLE "ensembles" DROP COLUMN "last_used";
|
||||
ALTER TABLE "ensembles" DROP COLUMN "last_played";
|
||||
|
||||
ALTER TABLE "recordings" DROP COLUMN "last_used";
|
||||
ALTER TABLE "recordings" DROP COLUMN "last_played";
|
||||
|
||||
ALTER TABLE "mediums" DROP COLUMN "last_used";
|
||||
ALTER TABLE "mediums" DROP COLUMN "last_played";
|
||||
|
||||
ALTER TABLE "tracks" DROP COLUMN "last_used";
|
||||
ALTER TABLE "tracks" DROP COLUMN "last_played";
|
||||
21
database/migrations/2022-04-10-103835_access_history/up.sql
Normal file
21
database/migrations/2022-04-10-103835_access_history/up.sql
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
ALTER TABLE "persons" ADD COLUMN "last_used" BIGINT;
|
||||
ALTER TABLE "persons" ADD COLUMN "last_played" BIGINT;
|
||||
|
||||
ALTER TABLE "instruments" ADD COLUMN "last_used" BIGINT;
|
||||
ALTER TABLE "instruments" ADD COLUMN "last_played" BIGINT;
|
||||
|
||||
ALTER TABLE "works" ADD COLUMN "last_used" BIGINT;
|
||||
ALTER TABLE "works" ADD COLUMN "last_played" BIGINT;
|
||||
|
||||
ALTER TABLE "ensembles" ADD COLUMN "last_used" BIGINT;
|
||||
ALTER TABLE "ensembles" ADD COLUMN "last_played" BIGINT;
|
||||
|
||||
ALTER TABLE "recordings" ADD COLUMN "last_used" BIGINT;
|
||||
ALTER TABLE "recordings" ADD COLUMN "last_played" BIGINT;
|
||||
|
||||
ALTER TABLE "mediums" ADD COLUMN "last_used" BIGINT;
|
||||
ALTER TABLE "mediums" ADD COLUMN "last_played" BIGINT;
|
||||
|
||||
ALTER TABLE "tracks" ADD COLUMN "last_used" BIGINT;
|
||||
ALTER TABLE "tracks" ADD COLUMN "last_played" BIGINT;
|
||||
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
use super::schema::ensembles;
|
||||
use super::{Database, Result};
|
||||
use chrono::Utc;
|
||||
use diesel::prelude::*;
|
||||
use log::info;
|
||||
|
||||
|
|
@ -8,14 +9,29 @@ use log::info;
|
|||
pub struct Ensemble {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub last_used: Option<i64>,
|
||||
pub last_played: Option<i64>,
|
||||
}
|
||||
|
||||
impl Ensemble {
|
||||
pub fn new(id: String, name: String) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
last_used: Some(Utc::now().timestamp()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Database {
|
||||
/// Update an existing ensemble or insert a new one.
|
||||
pub fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> {
|
||||
pub fn update_ensemble(&self, mut ensemble: Ensemble) -> Result<()> {
|
||||
info!("Updating ensemble {:?}", ensemble);
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
ensemble.last_used = Some(Utc::now().timestamp());
|
||||
|
||||
self.connection.transaction(|| {
|
||||
diesel::replace_into(ensembles::table)
|
||||
.values(ensemble)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::schema::instruments;
|
||||
use super::{Database, Result};
|
||||
use chrono::Utc;
|
||||
use diesel::prelude::*;
|
||||
use log::info;
|
||||
|
||||
|
|
@ -8,14 +9,29 @@ use log::info;
|
|||
pub struct Instrument {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub last_used: Option<i64>,
|
||||
pub last_played: Option<i64>,
|
||||
}
|
||||
|
||||
impl Instrument {
|
||||
pub fn new(id: String, name: String) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
last_used: Some(Utc::now().timestamp()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Database {
|
||||
/// Update an existing instrument or insert a new one.
|
||||
pub fn update_instrument(&self, instrument: Instrument) -> Result<()> {
|
||||
pub fn update_instrument(&self, mut instrument: Instrument) -> Result<()> {
|
||||
info!("Updating instrument {:?}", instrument);
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
instrument.last_used = Some(Utc::now().timestamp());
|
||||
|
||||
self.connection.transaction(|| {
|
||||
diesel::replace_into(instruments::table)
|
||||
.values(instrument)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use super::generate_id;
|
||||
use super::schema::{ensembles, mediums, performances, persons, recordings, tracks};
|
||||
use super::{Database, Error, Recording, Result};
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use diesel::prelude::*;
|
||||
use log::info;
|
||||
|
||||
|
|
@ -19,6 +20,22 @@ pub struct Medium {
|
|||
|
||||
/// The tracks of the medium.
|
||||
pub tracks: Vec<Track>,
|
||||
|
||||
pub last_used: Option<DateTime<Utc>>,
|
||||
pub last_played: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Medium {
|
||||
pub fn new(id: String, name: String, discid: Option<String>, tracks: Vec<Track>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
discid,
|
||||
tracks,
|
||||
last_used: Some(Utc::now()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A track on a medium.
|
||||
|
|
@ -37,6 +54,22 @@ pub struct Track {
|
|||
|
||||
/// The path to the audio file containing this track.
|
||||
pub path: String,
|
||||
|
||||
pub last_used: Option<DateTime<Utc>>,
|
||||
pub last_played: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Track {
|
||||
pub fn new(recording: Recording, work_parts: Vec<usize>, source_index: usize, path: String) -> Self {
|
||||
Self {
|
||||
recording,
|
||||
work_parts,
|
||||
source_index,
|
||||
path,
|
||||
last_used: Some(Utc::now()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Table data for a [`Medium`].
|
||||
|
|
@ -46,6 +79,8 @@ struct MediumRow {
|
|||
pub id: String,
|
||||
pub name: String,
|
||||
pub discid: Option<String>,
|
||||
pub last_used: Option<i64>,
|
||||
pub last_played: Option<i64>,
|
||||
}
|
||||
|
||||
/// Table data for a [`Track`].
|
||||
|
|
@ -59,6 +94,8 @@ struct TrackRow {
|
|||
pub work_parts: String,
|
||||
pub source_index: i32,
|
||||
pub path: String,
|
||||
pub last_used: Option<i64>,
|
||||
pub last_played: Option<i64>,
|
||||
}
|
||||
|
||||
impl Database {
|
||||
|
|
@ -79,6 +116,8 @@ impl Database {
|
|||
id: medium_id.to_owned(),
|
||||
name: medium.name.clone(),
|
||||
discid: medium.discid.clone(),
|
||||
last_used: Some(Utc::now().timestamp()),
|
||||
last_played: medium.last_played.map(|t| t.timestamp()),
|
||||
};
|
||||
|
||||
diesel::insert_into(mediums::table)
|
||||
|
|
@ -109,6 +148,8 @@ impl Database {
|
|||
work_parts,
|
||||
source_index: track.source_index as i32,
|
||||
path: track.path.clone(),
|
||||
last_used: Some(Utc::now().timestamp()),
|
||||
last_played: track.last_played.map(|t| t.timestamp()),
|
||||
};
|
||||
|
||||
diesel::insert_into(tracks::table)
|
||||
|
|
@ -254,6 +295,8 @@ impl Database {
|
|||
name: row.name,
|
||||
discid: row.discid,
|
||||
tracks,
|
||||
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
|
||||
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
|
||||
};
|
||||
|
||||
Ok(medium)
|
||||
|
|
@ -285,6 +328,8 @@ impl Database {
|
|||
work_parts: part_indices,
|
||||
source_index: row.source_index as usize,
|
||||
path: row.path,
|
||||
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
|
||||
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
|
||||
};
|
||||
|
||||
Ok(track)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::schema::persons;
|
||||
use super::{Database, Result};
|
||||
use chrono::Utc;
|
||||
use diesel::prelude::*;
|
||||
use log::info;
|
||||
|
||||
|
|
@ -9,9 +10,21 @@ pub struct Person {
|
|||
pub id: String,
|
||||
pub first_name: String,
|
||||
pub last_name: String,
|
||||
pub last_used: Option<i64>,
|
||||
pub last_played: Option<i64>,
|
||||
}
|
||||
|
||||
impl Person {
|
||||
pub fn new(id: String, first_name: String, last_name: String) -> Self {
|
||||
Self {
|
||||
id,
|
||||
first_name,
|
||||
last_name,
|
||||
last_used: Some(Utc::now().timestamp()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the full name in the form "First Last".
|
||||
pub fn name_fl(&self) -> String {
|
||||
format!("{} {}", self.first_name, self.last_name)
|
||||
|
|
@ -25,10 +38,12 @@ impl Person {
|
|||
|
||||
impl Database {
|
||||
/// Update an existing person or insert a new one.
|
||||
pub fn update_person(&self, person: Person) -> Result<()> {
|
||||
pub fn update_person(&self, mut person: Person) -> Result<()> {
|
||||
info!("Updating person {:?}", person);
|
||||
self.defer_foreign_keys()?;
|
||||
|
||||
person.last_used = Some(Utc::now().timestamp());
|
||||
|
||||
self.connection.transaction(|| {
|
||||
diesel::replace_into(persons::table)
|
||||
.values(person)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use super::generate_id;
|
||||
use super::schema::{ensembles, performances, persons, recordings};
|
||||
use super::{Database, Ensemble, Error, Instrument, Person, Result, Work};
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use diesel::prelude::*;
|
||||
use log::info;
|
||||
|
||||
|
|
@ -11,16 +12,31 @@ pub struct Recording {
|
|||
pub work: Work,
|
||||
pub comment: String,
|
||||
pub performances: Vec<Performance>,
|
||||
pub last_used: Option<DateTime<Utc>>,
|
||||
pub last_played: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Recording {
|
||||
pub fn new(id: String, work: Work, comment: String, performances: Vec<Performance>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
work,
|
||||
comment,
|
||||
performances,
|
||||
last_used: Some(Utc::now()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize a new recording with a work.
|
||||
pub fn new(work: Work) -> Self {
|
||||
pub fn from_work(work: Work) -> Self {
|
||||
Self {
|
||||
id: generate_id(),
|
||||
work,
|
||||
comment: String::new(),
|
||||
performances: Vec::new(),
|
||||
last_used: Some(Utc::now()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,6 +98,8 @@ struct RecordingRow {
|
|||
pub id: String,
|
||||
pub work: String,
|
||||
pub comment: String,
|
||||
pub last_used: Option<i64>,
|
||||
pub last_played: Option<i64>,
|
||||
}
|
||||
|
||||
impl From<Recording> for RecordingRow {
|
||||
|
|
@ -90,6 +108,8 @@ impl From<Recording> for RecordingRow {
|
|||
id: recording.id,
|
||||
work: recording.work.id,
|
||||
comment: recording.comment,
|
||||
last_used: Some(Utc::now().timestamp()),
|
||||
last_played: recording.last_played.map(|t| t.timestamp()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -255,6 +275,8 @@ impl Database {
|
|||
work,
|
||||
comment: row.comment,
|
||||
performances: performance_descriptions,
|
||||
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
|
||||
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
|
||||
};
|
||||
|
||||
Ok(recording_description)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ table! {
|
|||
ensembles (id) {
|
||||
id -> Text,
|
||||
name -> Text,
|
||||
last_used -> Nullable<BigInt>,
|
||||
last_played -> Nullable<BigInt>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -17,6 +19,8 @@ table! {
|
|||
instruments (id) {
|
||||
id -> Text,
|
||||
name -> Text,
|
||||
last_used -> Nullable<BigInt>,
|
||||
last_played -> Nullable<BigInt>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +29,8 @@ table! {
|
|||
id -> Text,
|
||||
name -> Text,
|
||||
discid -> Nullable<Text>,
|
||||
last_used -> Nullable<BigInt>,
|
||||
last_played -> Nullable<BigInt>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -43,6 +49,8 @@ table! {
|
|||
id -> Text,
|
||||
first_name -> Text,
|
||||
last_name -> Text,
|
||||
last_used -> Nullable<BigInt>,
|
||||
last_played -> Nullable<BigInt>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +59,8 @@ table! {
|
|||
id -> Text,
|
||||
work -> Text,
|
||||
comment -> Text,
|
||||
last_used -> Nullable<BigInt>,
|
||||
last_played -> Nullable<BigInt>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +73,8 @@ table! {
|
|||
work_parts -> Text,
|
||||
source_index -> Integer,
|
||||
path -> Text,
|
||||
last_used -> Nullable<BigInt>,
|
||||
last_played -> Nullable<BigInt>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +92,8 @@ table! {
|
|||
id -> Text,
|
||||
composer -> Text,
|
||||
title -> Text,
|
||||
last_used -> Nullable<BigInt>,
|
||||
last_played -> Nullable<BigInt>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use super::generate_id;
|
||||
use super::schema::{instrumentations, work_parts, works};
|
||||
use super::{Database, Error, Instrument, Person, Result};
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use diesel::prelude::*;
|
||||
use diesel::{Insertable, Queryable};
|
||||
use log::info;
|
||||
|
|
@ -12,6 +13,8 @@ struct WorkRow {
|
|||
pub id: String,
|
||||
pub composer: String,
|
||||
pub title: String,
|
||||
pub last_used: Option<i64>,
|
||||
pub last_played: Option<i64>,
|
||||
}
|
||||
|
||||
impl From<Work> for WorkRow {
|
||||
|
|
@ -20,6 +23,8 @@ impl From<Work> for WorkRow {
|
|||
id: work.id,
|
||||
composer: work.composer.id,
|
||||
title: work.title,
|
||||
last_used: Some(Utc::now().timestamp()),
|
||||
last_played: work.last_played.map(|t| t.timestamp()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -57,17 +62,33 @@ pub struct Work {
|
|||
pub composer: Person,
|
||||
pub instruments: Vec<Instrument>,
|
||||
pub parts: Vec<WorkPart>,
|
||||
pub last_used: Option<DateTime<Utc>>,
|
||||
pub last_played: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Work {
|
||||
pub fn new(id: String, title: String, composer: Person, instruments: Vec<Instrument>, parts: Vec<WorkPart>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
title,
|
||||
composer,
|
||||
instruments,
|
||||
parts,
|
||||
last_used: Some(Utc::now()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize a new work with a composer.
|
||||
pub fn new(composer: Person) -> Self {
|
||||
pub fn from_composer(composer: Person) -> Self {
|
||||
Self {
|
||||
id: generate_id(),
|
||||
title: String::new(),
|
||||
composer,
|
||||
instruments: Vec::new(),
|
||||
parts: Vec::new(),
|
||||
last_used: Some(Utc::now()),
|
||||
last_played: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,9 +130,7 @@ impl Database {
|
|||
.execute(&self.connection)?;
|
||||
|
||||
let Work {
|
||||
instruments,
|
||||
parts,
|
||||
..
|
||||
instruments, parts, ..
|
||||
} = work;
|
||||
|
||||
for instrument in instruments {
|
||||
|
|
@ -200,6 +219,8 @@ impl Database {
|
|||
title: row.title,
|
||||
instruments,
|
||||
parts,
|
||||
last_used: row.last_used.map(|t| Utc.timestamp(t, 0)),
|
||||
last_played: row.last_played.map(|t| Utc.timestamp(t, 0)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,10 +88,7 @@ impl EnsembleEditor {
|
|||
fn save(&self) -> Result<Ensemble> {
|
||||
let name = self.name.get_text();
|
||||
|
||||
let ensemble = Ensemble {
|
||||
id: self.id.clone(),
|
||||
name,
|
||||
};
|
||||
let ensemble = Ensemble::new(self.id.clone(), name);
|
||||
|
||||
self.handle.backend.db().update_ensemble(ensemble.clone())?;
|
||||
self.handle.backend.library_changed();
|
||||
|
|
|
|||
|
|
@ -88,12 +88,12 @@ impl InstrumentEditor {
|
|||
fn save(&self) -> Result<Instrument> {
|
||||
let name = self.name.get_text();
|
||||
|
||||
let instrument = Instrument {
|
||||
id: self.id.clone(),
|
||||
name,
|
||||
};
|
||||
let instrument = Instrument::new(self.id.clone(), name);
|
||||
|
||||
self.handle.backend.db().update_instrument(instrument.clone())?;
|
||||
self.handle
|
||||
.backend
|
||||
.db()
|
||||
.update_instrument(instrument.clone())?;
|
||||
self.handle.backend.library_changed();
|
||||
|
||||
Ok(instrument)
|
||||
|
|
|
|||
|
|
@ -102,11 +102,7 @@ impl PersonEditor {
|
|||
let first_name = self.first_name.get_text();
|
||||
let last_name = self.last_name.get_text();
|
||||
|
||||
let person = Person {
|
||||
id: self.id.clone(),
|
||||
first_name,
|
||||
last_name,
|
||||
};
|
||||
let person = Person::new(self.id.clone(), first_name, last_name);
|
||||
|
||||
self.handle.backend.db().update_person(person.clone())?;
|
||||
self.handle.backend.library_changed();
|
||||
|
|
|
|||
|
|
@ -177,18 +177,20 @@ impl RecordingEditor {
|
|||
|
||||
/// Save the recording.
|
||||
fn save(self: &Rc<Self>) -> Result<Recording> {
|
||||
let recording = Recording {
|
||||
id: self.id.clone(),
|
||||
work: self
|
||||
.work
|
||||
let recording = Recording::new(
|
||||
self.id.clone(),
|
||||
self.work
|
||||
.borrow()
|
||||
.clone()
|
||||
.expect("Tried to create recording without work!"),
|
||||
comment: self.comment_entry.text().to_string(),
|
||||
performances: self.performances.borrow().clone(),
|
||||
};
|
||||
self.comment_entry.text().to_string(),
|
||||
self.performances.borrow().clone(),
|
||||
);
|
||||
|
||||
self.handle.backend.db().update_recording(recording.clone())?;
|
||||
self.handle
|
||||
.backend
|
||||
.db()
|
||||
.update_recording(recording.clone())?;
|
||||
self.handle.backend.library_changed();
|
||||
|
||||
Ok(recording)
|
||||
|
|
|
|||
|
|
@ -148,52 +148,53 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
});
|
||||
}));
|
||||
|
||||
this.part_list.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
|
||||
let part = &this.parts.borrow()[index];
|
||||
this.part_list
|
||||
.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
|
||||
let part = &this.parts.borrow()[index];
|
||||
|
||||
let delete_button = gtk::Button::from_icon_name(Some("user-trash-symbolic"));
|
||||
delete_button.set_valign(gtk::Align::Center);
|
||||
let delete_button = gtk::Button::from_icon_name(Some("user-trash-symbolic"));
|
||||
delete_button.set_valign(gtk::Align::Center);
|
||||
|
||||
delete_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
let length = {
|
||||
let mut structure = this.parts.borrow_mut();
|
||||
structure.remove(index);
|
||||
structure.len()
|
||||
};
|
||||
delete_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
let length = {
|
||||
let mut structure = this.parts.borrow_mut();
|
||||
structure.remove(index);
|
||||
structure.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
this.part_list.update(length);
|
||||
}));
|
||||
|
||||
let edit_button = gtk::Button::from_icon_name(Some("document-edit-symbolic"));
|
||||
edit_button.set_valign(gtk::Align::Center);
|
||||
|
||||
edit_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
spawn!(@clone this, async move {
|
||||
let part = this.parts.borrow()[index].clone();
|
||||
if let Some(part) = push!(this.handle, WorkPartEditor, Some(part)).await {
|
||||
let length = {
|
||||
let mut structure = this.parts.borrow_mut();
|
||||
structure[index] = part;
|
||||
structure.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
let row = adw::ActionRowBuilder::new()
|
||||
.focusable(false)
|
||||
.title(&part.title)
|
||||
.activatable_widget(&edit_button)
|
||||
.build();
|
||||
|
||||
row.add_suffix(&delete_button);
|
||||
row.add_suffix(&edit_button);
|
||||
|
||||
row.upcast()
|
||||
}));
|
||||
|
||||
let edit_button = gtk::Button::from_icon_name(Some("document-edit-symbolic"));
|
||||
edit_button.set_valign(gtk::Align::Center);
|
||||
|
||||
edit_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
spawn!(@clone this, async move {
|
||||
let part = this.parts.borrow()[index].clone();
|
||||
if let Some(part) = push!(this.handle, WorkPartEditor, Some(part)).await {
|
||||
let length = {
|
||||
let mut structure = this.parts.borrow_mut();
|
||||
structure[index] = part;
|
||||
structure.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
let row = adw::ActionRowBuilder::new()
|
||||
.focusable(false)
|
||||
.title(&part.title)
|
||||
.activatable_widget(&edit_button)
|
||||
.build();
|
||||
|
||||
row.add_suffix(&delete_button);
|
||||
row.add_suffix(&edit_button);
|
||||
|
||||
row.upcast()
|
||||
}));
|
||||
|
||||
this.part_list
|
||||
.set_move_cb(clone!(@weak this => move |old_index, new_index| {
|
||||
let length = {
|
||||
|
|
@ -248,17 +249,16 @@ impl WorkEditor {
|
|||
|
||||
/// Save the work.
|
||||
fn save(self: &Rc<Self>) -> Result<Work> {
|
||||
let work = Work {
|
||||
id: self.id.clone(),
|
||||
title: self.title_entry.text().to_string(),
|
||||
composer: self
|
||||
.composer
|
||||
let work = Work::new(
|
||||
self.id.clone(),
|
||||
self.title_entry.text().to_string(),
|
||||
self.composer
|
||||
.borrow()
|
||||
.clone()
|
||||
.expect("Tried to create work without composer!"),
|
||||
instruments: self.instruments.borrow().clone(),
|
||||
parts: self.parts.borrow().clone(),
|
||||
};
|
||||
self.instruments.borrow().clone(),
|
||||
self.parts.borrow().clone(),
|
||||
);
|
||||
|
||||
self.handle.backend.db().update_work(work.clone())?;
|
||||
self.handle.backend.library_changed();
|
||||
|
|
|
|||
|
|
@ -186,23 +186,23 @@ impl MediumEditor {
|
|||
|
||||
for track_set_data in &*self.track_sets.borrow() {
|
||||
for track_data in &track_set_data.tracks {
|
||||
let track = Track {
|
||||
recording: track_set_data.recording.clone(),
|
||||
work_parts: track_data.work_parts.clone(),
|
||||
source_index: track_data.track_source,
|
||||
path: String::new(),
|
||||
};
|
||||
let track = Track::new(
|
||||
track_set_data.recording.clone(),
|
||||
track_data.work_parts.clone(),
|
||||
track_data.track_source,
|
||||
String::new(),
|
||||
);
|
||||
|
||||
tracks.push(track);
|
||||
}
|
||||
}
|
||||
|
||||
let medium = Medium {
|
||||
id: generate_id(),
|
||||
name: self.name_entry.text().to_string(),
|
||||
discid: Some(self.session.source_id().to_owned()),
|
||||
let medium = Medium::new(
|
||||
generate_id(),
|
||||
self.name_entry.text().to_string(),
|
||||
Some(self.session.source_id().to_owned()),
|
||||
tracks,
|
||||
};
|
||||
);
|
||||
|
||||
// The medium is not added to the database, because the track paths are not known until the
|
||||
// medium is actually imported into the music library. This step will be handled by the
|
||||
|
|
|
|||
|
|
@ -248,12 +248,12 @@ impl MediumPreview {
|
|||
|
||||
// Add the modified medium to the database.
|
||||
|
||||
let medium = Medium {
|
||||
id: medium.id.clone(),
|
||||
name: medium.name.clone(),
|
||||
discid: medium.discid.clone(),
|
||||
let medium = Medium::new(
|
||||
medium.id.clone(),
|
||||
medium.name.clone(),
|
||||
medium.discid.clone(),
|
||||
tracks,
|
||||
};
|
||||
);
|
||||
|
||||
self.handle.backend.db().update_medium(medium)?;
|
||||
self.handle.backend.library_changed();
|
||||
|
|
|
|||
|
|
@ -36,12 +36,12 @@ impl Screen<(), Recording> for RecordingSelector {
|
|||
// immediately show the work editor. Going back from the work editor will
|
||||
// correctly show the person selector again.
|
||||
|
||||
let work = Work::new(person);
|
||||
let work = Work::from_composer(person);
|
||||
if let Some(work) = push!(this.handle, WorkEditor, Some(work)).await {
|
||||
// There will also be no existing recordings, so we show the recording
|
||||
// editor next.
|
||||
|
||||
let recording = Recording::new(work);
|
||||
let recording = Recording::from_work(work);
|
||||
if let Some(recording) = push!(this.handle, RecordingEditor, Some(recording)).await {
|
||||
this.handle.pop(Some(recording));
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ impl Screen<Person, Work> for RecordingSelectorWorkScreen {
|
|||
|
||||
this.selector.set_add_cb(clone!(@weak this => move || {
|
||||
spawn!(@clone this, async move {
|
||||
let work = Work::new(this.person.clone());
|
||||
let work = Work::from_composer(this.person.clone());
|
||||
if let Some(work) = push!(this.handle, WorkEditor, Some(work)).await {
|
||||
this.handle.pop(Some(work));
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ impl Screen<Work, Recording> for RecordingSelectorRecordingScreen {
|
|||
|
||||
this.selector.set_add_cb(clone!(@weak this => move || {
|
||||
spawn!(@clone this, async move {
|
||||
let recording = Recording::new(this.work.clone());
|
||||
let recording = Recording::from_work(this.work.clone());
|
||||
if let Some(recording) = push!(this.handle, RecordingEditor, Some(recording)).await {
|
||||
this.handle.pop(Some(recording));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ impl Screen<(), Work> for WorkSelector {
|
|||
// immediately show the work editor. Going back from the work editor will
|
||||
// correctly show the person selector again.
|
||||
|
||||
let work = Work::new(person);
|
||||
let work = Work::from_composer(person);
|
||||
if let Some(work) = push!(this.handle, WorkEditor, Some(work)).await {
|
||||
this.handle.pop(Some(work));
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ impl Screen<Person, Work> for WorkSelectorWorkScreen {
|
|||
|
||||
this.selector.set_add_cb(clone!(@weak this => move || {
|
||||
spawn!(@clone this, async move {
|
||||
let work = Work::new(this.person.clone());
|
||||
let work = Work::from_composer(this.person.clone());
|
||||
if let Some(work) = push!(this.handle, WorkEditor, Some(work)).await {
|
||||
this.handle.pop(Some(work));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue