client: Add client specific database

This commit is contained in:
Elias Projahn 2020-06-02 16:47:46 +02:00
parent dfeaefd0b3
commit cd8d1dfe4b
31 changed files with 701 additions and 35 deletions

7
client/build.yaml Normal file
View file

@ -0,0 +1,7 @@
targets:
$default:
builders:
moor_generator:
options:
generate_connect_constructor: true
use_column_name_as_json_key_when_defined_in_moor_file: false

View file

@ -1 +1,3 @@
export 'src/client.dart';
export 'src/client.dart';
export 'src/database.dart';
export 'src/info.dart';

View file

@ -3,7 +3,9 @@ import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
import 'package:musicus_database/musicus_database.dart';
import 'database.dart';
import 'info.dart';
/// Credentials for a Musicus account.
class MusicusAccountCredentials {

View file

@ -0,0 +1,351 @@
import 'dart:math';
import 'package:moor/moor.dart';
import 'package:musicus_client/musicus_client.dart';
import 'info.dart';
part 'database.g.dart';
final _random = Random(DateTime.now().millisecondsSinceEpoch);
/// Generate a random ID suitable for use as primary key.
int generateId() => _random.nextInt(0xFFFFFFFF);
/// The database for storing all metadata for the music library.
///
/// This also handles synchronization with a Musicus server.
@UseMoor(include: {'database.moor'})
class MusicusClientDatabase extends _$MusicusClientDatabase {
/// The number of items contained in one result page.
static const pageSize = 50;
/// The client to use for synchronization.
///
/// This may be null indicating that everything should be kept local.
final MusicusClient client;
@override
int get schemaVersion => 1;
@override
MigrationStrategy get migration => MigrationStrategy(
beforeOpen: (details) async {
await customStatement('PRAGMA foreign_keys = ON');
},
);
MusicusClientDatabase({
@required QueryExecutor executor,
this.client,
}) : super(executor);
MusicusClientDatabase.connect({
@required DatabaseConnection connection,
this.client,
}) : super.connect(connection);
/// Get all available persons.
///
/// This will return a list of [pageSize] persons. You can get another page
/// using the [page] parameter. If a non empty [search] string is provided,
/// the persons will get filtered based on that string.
Future<List<Person>> getPersons([int page, String search]) async {
final offset = page != null ? page * pageSize : 0;
List<Person> result;
if (search == null || search.isEmpty) {
result = await allPersons(pageSize, offset).get();
} else {
result = await searchPersons('$search%', pageSize, offset).get();
}
return result;
}
/// Add [person] or replace an existing person with the same ID.
Future<void> updatePerson(Person person) async {
await into(persons).insert(
person,
mode: InsertMode.insertOrReplace,
);
}
/// Delete the person by [id].
Future<void> deletePerson(int id) async {
await (delete(persons)..where((p) => p.id.equals(id))).go();
}
/// Get all available instruments.
///
/// This will return a list of [pageSize] instruments. You can get another
/// page using the [page] parameter. If a non empty [search] string is
/// provided, the instruments will get filtered based on that string.
Future<List<Instrument>> getInstruments([int page, String search]) async {
final offset = page != null ? page * pageSize : 0;
List<Instrument> result;
if (search == null || search.isEmpty) {
result = await allInstruments(pageSize, offset).get();
} else {
result = await searchInstruments('$search%', pageSize, offset).get();
}
return result;
}
/// Add [instrument] or replace an existing one with the same ID.
Future<void> updateInstrument(Instrument instrument) async {
await into(instruments).insert(
instrument,
mode: InsertMode.insertOrReplace,
);
}
/// Delete the instrument by [id].
Future<void> deleteInstrument(int id) async {
await (delete(instruments)..where((i) => i.id.equals(id))).go();
}
/// Retrieve more information on an already queried work.
Future<WorkInfo> getWorkInfo(Work work) async {
final id = work.id;
final composers = await partComposersByWork(id).get();
composers.insert(0, await personById(work.composer).getSingle());
final instruments = await instrumentsByWork(id).get();
final List<PartInfo> parts = [];
for (final part in await partsByWork(id).get()) {
parts.add(PartInfo(
part: part,
composer: part.composer != null
? await personById(part.composer).getSingle()
: null,
instruments: await instrumentsByWorkPart(part.id).get(),
));
}
final List<WorkSection> sections = [];
for (final section in await sectionsByWork(id).get()) {
sections.add(section);
}
return WorkInfo(
work: work,
instruments: instruments,
composers: composers,
parts: parts,
sections: sections,
);
}
/// Get all available information on a work.
Future<WorkInfo> getWork(int id) async {
final work = await workById(id).getSingle();
return await getWorkInfo(work);
}
/// Get information on all works written by the person with ID [personId].
///
/// This will return a list of [pageSize] results. You can get another page
/// using the [page] parameter. If a non empty [search] string is provided,
/// the works will be filtered using that string.
Future<List<WorkInfo>> getWorks(int personId,
[int page, String search]) async {
final offset = page != null ? page * pageSize : 0;
List<Work> works;
if (search == null || search.isEmpty) {
works = await worksByComposer(personId, pageSize, offset).get();
} else {
works =
await searchWorksByComposer(personId, '$search%', pageSize, offset)
.get();
}
final List<WorkInfo> result = [];
for (final work in works) {
result.add(await getWorkInfo(work));
}
return result;
}
/// Add or replace a work and its associated data.
///
/// This will explicitly update all associated composers and instruments, even
/// if they have already existed before.
Future<void> updateWork(WorkInfo workInfo) async {
await transaction(() async {
final workId = workInfo.work.id;
// Delete old work data first. The parts, sections and instrumentations
// will be deleted automatically due to their foreign key constraints.
await deleteWork(workId);
// This will also include the composers of the work's parts.
for (final person in workInfo.composers) {
await updatePerson(person);
}
await into(works).insert(workInfo.work);
// At the moment, this will also update all provided instruments, even if
// they were already there previously.
for (final instrument in workInfo.instruments) {
await updateInstrument(instrument);
await into(instrumentations).insert(Instrumentation(
work: workId,
instrument: instrument.id,
));
}
for (final partInfo in workInfo.parts) {
final part = partInfo.part;
await into(workParts).insert(part);
for (final instrument in workInfo.instruments) {
await updateInstrument(instrument);
await into(partInstrumentations).insert(PartInstrumentation(
workPart: part.id,
instrument: instrument.id,
));
}
}
for (final section in workInfo.sections) {
await into(workSections).insert(section);
}
});
}
/// Delete the work by [id].
Future<void> deleteWork(int id) async {
// The parts and instrumentations will be deleted automatically due to
// their foreign key constraints.
await (delete(works)..where((w) => w.id.equals(id))).go();
}
/// Get all available ensembles.
///
/// This will return a list of [pageSize] ensembles. You can get another page
/// using the [page] parameter. If a non empty [search] string is provided,
/// the ensembles will get filtered based on that string.
Future<List<Ensemble>> getEnsembles([int page, String search]) async {
final offset = page != null ? page * pageSize : 0;
List<Ensemble> result;
if (search == null || search.isEmpty) {
result = await allEnsembles(pageSize, offset).get();
} else {
result = await searchEnsembles('$search%', pageSize, offset).get();
}
return result;
}
/// Add [ensemble] or replace an existing one with the same ID.
Future<void> updateEnsemble(Ensemble ensemble) async {
await into(ensembles).insert(
ensemble,
mode: InsertMode.insertOrReplace,
);
}
/// Delete the ensemble by [id].
Future<void> deleteEnsemble(int id) async {
await (delete(ensembles)..where((e) => e.id.equals(id))).go();
}
/// Add or replace a recording and its associated data.
///
/// This will explicitly also update all assoicated persons and instruments.
Future<void> updateRecording(RecordingInfo recordingInfo) async {
await transaction(() async {
final recordingId = recordingInfo.recording.id;
// Delete the old recording first. This will also delete the performances
// due to their foreign key constraint.
await deleteRecording(recordingId);
await into(recordings).insert(recordingInfo.recording);
for (final performance in recordingInfo.performances) {
if (performance.person != null) {
await updatePerson(performance.person);
}
if (performance.ensemble != null) {
await updateEnsemble(performance.ensemble);
}
if (performance.role != null) {
await updateInstrument(performance.role);
}
await into(performances).insert(Performance(
recording: recordingId,
person: performance.person?.id,
ensemble: performance.ensemble?.id,
role: performance.role?.id,
));
}
});
}
/// Retreive more information on an already queried recording.
Future<RecordingInfo> getRecordingInfo(Recording recording) async {
final id = recording.id;
final List<PerformanceInfo> performances = [];
for (final performance in await performancesByRecording(id).get()) {
performances.add(PerformanceInfo(
person: performance.person != null
? await personById(performance.person).getSingle()
: null,
ensemble: performance.ensemble != null
? await ensembleById(performance.ensemble).getSingle()
: null,
role: performance.role != null
? await instrumentById(performance.role).getSingle()
: null,
));
}
return RecordingInfo(
recording: recording,
performances: performances,
);
}
/// Get all available information on a recording.
Future<RecordingInfo> getRecording(int id) async {
final recording = await recordingById(id).getSingle();
return await getRecordingInfo(recording);
}
/// Delete a recording by [id].
Future<void> deleteRecording(int id) async {
// This will also delete the performances due to their foreign key
// constraint.
await (delete(recordings)..where((r) => r.id.equals(id))).go();
}
/// Get information on all recordings of the work with ID [workId].
///
/// This will return a list of [pageSize] recordings. You can get the other
/// pages using the [page] parameter.
Future<List<RecordingInfo>> getRecordings(int workId, [int page]) async {
final offset = page != null ? page * pageSize : 0;
final recordings = await recordingsByWork(workId, pageSize, offset).get();
final List<RecordingInfo> result = [];
for (final recording in recordings) {
result.add(await getRecordingInfo(recording));
}
return result;
}
}

View file

@ -0,0 +1,149 @@
CREATE TABLE persons (
id INTEGER NOT NULL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
sync BOOLEAN NOT NULL DEFAULT FALSE,
synced BOOLEAN NOT NULL DEFAULT FALSE
);
-- This represents real instruments as well as other roles that can be played
-- in a recording.
CREATE TABLE instruments (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
sync BOOLEAN NOT NULL DEFAULT FALSE,
synced BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE works (
id INTEGER NOT NULL PRIMARY KEY,
composer INTEGER REFERENCES persons(id) ON DELETE SET NULL,
title TEXT NOT NULL,
sync BOOLEAN NOT NULL DEFAULT FALSE,
synced BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE instrumentations (
work INTEGER NOT NULL REFERENCES works(id) ON DELETE CASCADE,
instrument INTEGER NOT NULL REFERENCES instruments(id) ON DELETE CASCADE
);
CREATE TABLE work_parts (
id INTEGER NOT NULL PRIMARY KEY,
composer INTEGER REFERENCES persons(id) ON DELETE SET NULL,
title TEXT NOT NULL,
part_of INTEGER NOT NULL REFERENCES works(id) ON DELETE CASCADE,
part_index INTEGER NOT NULL
);
CREATE TABLE part_instrumentations (
work_part INTEGER NOT NULL REFERENCES works(id) ON DELETE CASCADE,
instrument INTEGER NOT NULL REFERENCES instruments(id) ON DELETE CASCADE
);
CREATE TABLE work_sections (
id INTEGER NOT NULL PRIMARY KEY,
work INTEGER NOT NULL REFERENCES works(id) ON DELETE CASCADE,
title TEXT NOT NULL,
before_part_index INTEGER NOT NULL
);
CREATE TABLE ensembles (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
sync BOOLEAN NOT NULL DEFAULT FALSE,
synced BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE recordings (
id INTEGER NOT NULL PRIMARY KEY,
work INTEGER REFERENCES works(id) ON DELETE SET NULL,
comment TEXT NOT NULL,
sync BOOLEAN NOT NULL DEFAULT FALSE,
synced BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE performances (
recording INTEGER NOT NULL REFERENCES recordings(id) ON DELETE CASCADE,
person INTEGER REFERENCES persons(id) ON DELETE CASCADE,
ensemble INTEGER REFERENCES ensembles(id) ON DELETE CASCADE,
role INTEGER REFERENCES instruments(id) ON DELETE SET NULL
);
allPersons:
SELECT * FROM persons ORDER BY last_name, first_name
LIMIT :limit OFFSET :offset;
searchPersons:
SELECT * FROM persons WHERE last_name LIKE :search
ORDER BY last_name, first_name LIMIT :limit OFFSET :offset;
personById:
SELECT * FROM persons WHERE id = :id LIMIT 1;
allInstruments:
SELECT * FROM instruments ORDER BY name LIMIT :limit OFFSET :offset;
searchInstruments:
SELECT * FROM instruments WHERE name LIKE :search ORDER BY name
LIMIT :limit OFFSET :offset;
instrumentById:
SELECT * FROM instruments WHERE id = :id LIMIT 1;
workById:
SELECT * FROM works WHERE id = :id LIMIT 1;
partsByWork:
SELECT * FROM work_parts WHERE part_of = :id ORDER BY part_index;
sectionsByWork:
SELECT * FROM work_sections WHERE work = :id ORDER BY before_part_index;
worksByComposer:
SELECT DISTINCT works.* FROM works
JOIN work_parts ON work_parts.part_of = works.id
WHERE works.composer = :id OR work_parts.composer = :id
ORDER BY works.title LIMIT :limit OFFSET :offset;
searchWorksByComposer:
SELECT DISTINCT works.* FROM works
JOIN work_parts ON work_parts.part_of = works.id
WHERE (works.composer = :id OR work_parts.composer = :id)
AND works.title LIKE :search
ORDER BY works.title LIMIT :limit OFFSET :offset;
partComposersByWork:
SELECT DISTINCT persons.* FROM persons
JOIN work_parts ON work_parts.composer = persons.id
WHERE work_parts.part_of = :id;
instrumentsByWork:
SELECT instruments.* FROM instrumentations
JOIN instruments ON instrumentations.instrument = instruments.id
WHERE instrumentations.work = :workId;
instrumentsByWorkPart:
SELECT instruments.* FROM part_instrumentations
JOIN instruments ON part_instrumentations.instrument = instruments.id
WHERE part_instrumentations.work_part = :id;
allEnsembles:
SELECT * FROM ensembles ORDER BY name LIMIT :limit OFFSET :offset;
searchEnsembles:
SELECT * FROM ensembles WHERE name LIKE :search ORDER BY name
LIMIT :limit OFFSET :offset;
ensembleById:
SELECT * FROM ensembles WHERE id = :id LIMIT 1;
recordingById:
SELECT * FROM recordings WHERE id = :id;
recordingsByWork:
SELECT * FROM recordings WHERE work = :id ORDER BY id
LIMIT :limit OFFSET :offset;
performancesByRecording:
SELECT * FROM performances WHERE recording = :id;

157
client/lib/src/info.dart Normal file
View file

@ -0,0 +1,157 @@
import 'database.dart';
/// A bundle of all available information on a work part.
class PartInfo {
/// The work part itself.
final WorkPart part;
/// A list of instruments.
///
/// This will include the instruments, that are specific to this part.
final List<Instrument> instruments;
/// The composer of this part.
///
/// This is null, if this part doesn't have a specific composer.
final Person composer;
PartInfo({
this.part,
this.instruments,
this.composer,
});
factory PartInfo.fromJson(Map<String, dynamic> json) => PartInfo(
part: WorkPart.fromJson(json['part']),
instruments: json['instruments']
.map<Instrument>((j) => Instrument.fromJson(j))
.toList(),
composer:
json['composer'] != null ? Person.fromJson(json['composer']) : null,
);
Map<String, dynamic> toJson() => {
'part': part.toJson(),
'instruments': instruments.map((i) => i.toJson()).toList(),
'composers': composer?.toJson(),
};
}
/// A bundle information on a work.
///
/// This includes all available information except for recordings of this work.
class WorkInfo {
/// The work itself.
final Work work;
/// A list of instruments.
///
/// This will not the include the instruments, that are specific to the work
/// parts.
final List<Instrument> instruments;
/// A list of persons, which will include all part composers.
final List<Person> composers;
/// All available information on the work parts.
final List<PartInfo> parts;
/// The sections of this work.
final List<WorkSection> sections;
WorkInfo({
this.work,
this.instruments,
this.composers,
this.parts,
this.sections,
});
factory WorkInfo.fromJson(Map<String, dynamic> json) => WorkInfo(
work: Work.fromJson(json['work']),
instruments: json['instruments']
.map<Instrument>((j) => Instrument.fromJson(j))
.toList(),
composers:
json['composers'].map<Person>((j) => Person.fromJson(j)).toList(),
parts:
json['parts'].map<PartInfo>((j) => PartInfo.fromJson(j)).toList(),
sections: json['sections']
.map<WorkSection>((j) => WorkSection.fromJson(j))
.toList(),
);
Map<String, dynamic> toJson() => {
'work': work.toJson(),
'instruments': instruments.map((i) => i.toJson()).toList(),
'composers': composers.map((c) => c.toJson()).toList(),
'parts': parts.map((c) => c.toJson()).toList(),
'sections': sections.map((s) => s.toJson()).toList(),
};
}
/// All available information on a performance within a recording.
class PerformanceInfo {
/// The performing person.
///
/// This will be null, if this is an ensemble.
final Person person;
/// The performing ensemble.
///
/// This will be null, if this is a person.
final Ensemble ensemble;
/// The instrument/role or null.
final Instrument role;
PerformanceInfo({
this.person,
this.ensemble,
this.role,
});
factory PerformanceInfo.fromJson(Map<String, dynamic> json) =>
PerformanceInfo(
person: json['person'] != null ? Person.fromJson(json['person']) : null,
ensemble: json['ensemble'] != null
? Ensemble.fromJson(json['ensemble'])
: null,
role: json['role'] != null ? Instrument.fromJson(json['role']) : null,
);
Map<String, dynamic> toJson() => {
'person': person?.toJson(),
'ensemble': ensemble?.toJson(),
'role': role?.toJson(),
};
}
/// All available information on a recording.
///
/// This doesn't include the recorded work, because probably it's already
/// available.
class RecordingInfo {
/// The recording itself.
final Recording recording;
/// Information on the performances within this recording.
final List<PerformanceInfo> performances;
RecordingInfo({
this.recording,
this.performances,
});
factory RecordingInfo.fromJson(Map<String, dynamic> json) => RecordingInfo(
recording: Recording.fromJson(json['recording']),
performances: json['performances']
.map<PerformanceInfo>((j) => PerformanceInfo.fromJson(j))
.toList(),
);
Map<String, dynamic> toJson() => {
'recording': recording.toJson(),
'performances': performances.map((p) => p.toJson()).toList(),
};
}

View file

@ -3,10 +3,13 @@ description: Client library for the Musicus server.
version: 0.0.1
environment:
sdk: ">=2.3.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"
dependencies:
http:
meta:
musicus_database:
path: ../database
moor:
dev_dependencies:
build_runner:
moor_generator:

View file

@ -7,7 +7,6 @@ import 'package:moor/isolate.dart';
import 'package:moor/moor.dart';
import 'package:moor_ffi/moor_ffi.dart';
import 'package:musicus_client/musicus_client.dart';
import 'package:musicus_database/musicus_database.dart';
import 'library.dart';
import 'platform.dart';
@ -97,7 +96,7 @@ class MusicusBackendState extends State<MusicusBackend> {
/// prevent all access to the backend.
MusicusBackendStatus status = MusicusBackendStatus.loading;
Database db;
MusicusClientDatabase db;
MusicusPlayback playback;
MusicusSettings settings;
MusicusClient client;
@ -122,7 +121,7 @@ class MusicusBackendState extends State<MusicusBackend> {
}
final moorIsolate = MoorIsolate.fromConnectPort(moorPort);
db = Database.connect(await moorIsolate.connect());
db = MusicusClientDatabase.connect(connection: await moorIsolate.connect());
playback = widget.playback;
await playback.setup();

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../selectors/ensemble.dart';
import '../selectors/instruments.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';
import '../editors/performance.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';
import '../library.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';
import '../selectors/instruments.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../editors/ensemble.dart';
import '../widgets/lists.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';
import '../editors/instrument.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../editors/person.dart';
import '../widgets/lists.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../editors/recording.dart';
import '../widgets/lists.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../editors/work.dart';
import '../widgets/lists.dart';

View file

@ -1,7 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import '../backend.dart';
import '../widgets/texts.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import 'texts.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
/// A widget showing information on a list of performances.
class PerformancesText extends StatelessWidget {

View file

@ -13,6 +13,4 @@ dependencies:
moor_ffi:
musicus_client:
path: ../client
musicus_database:
path: ../database
rxdart:

View file

@ -5,7 +5,7 @@ import 'dart:ui';
import 'package:audio_service/audio_service.dart';
import 'package:moor/isolate.dart';
import 'package:musicus_database/musicus_database.dart';
import 'package:musicus_client/musicus_client.dart';
import 'package:musicus_common/musicus_common.dart';
import 'package:musicus_player/musicus_player.dart';
@ -281,7 +281,7 @@ class _PlaybackService extends BackgroundAudioTask {
final _loading = Completer();
final List<InternalTrack> _playlist = [];
Database db;
MusicusClientDatabase db;
MusicusPlayer _player;
int _currentTrack = 0;
bool _playing = false;
@ -306,7 +306,7 @@ class _PlaybackService extends BackgroundAudioTask {
Future<void> _load() async {
final moorPort = IsolateNameServer.lookupPortByName('moor');
final moorIsolate = MoorIsolate.fromConnectPort(moorPort);
db = Database.connect(await moorIsolate.connect());
db = MusicusClientDatabase.connect(connection: await moorIsolate.connect());
_loading.complete();
}

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:musicus_client/musicus_client.dart';
import 'package:musicus_common/musicus_common.dart';
import 'package:musicus_database/musicus_database.dart';
import '../icons.dart';

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:musicus_client/musicus_client.dart';
import 'package:musicus_common/musicus_common.dart';
import 'package:musicus_database/musicus_database.dart';
import 'work.dart';

View file

@ -1,8 +1,8 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:musicus_client/musicus_client.dart';
import 'package:musicus_common/musicus_common.dart';
import 'package:musicus_database/musicus_database.dart';
import '../widgets/play_pause_button.dart';

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:musicus_client/musicus_client.dart';
import 'package:musicus_common/musicus_common.dart';
import 'package:musicus_database/musicus_database.dart';
class WorkScreen extends StatelessWidget {
final WorkInfo workInfo;

View file

@ -1,8 +1,8 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:musicus_client/musicus_client.dart';
import 'package:musicus_common/musicus_common.dart';
import 'package:musicus_database/musicus_database.dart';
import '../screens/program.dart';

View file

@ -20,8 +20,6 @@ dependencies:
path: ../client
musicus_common:
path: ../common
musicus_database:
path: ../database
musicus_player:
path: ../player
path: