From 0438296bcc21a79e72a3694c3c5440d80bdb519a Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Sun, 5 Apr 2020 19:31:46 +0200 Subject: [PATCH] Add recording selector As a proof of concept some widgets were seperated. The home screen now links to this instead of the recording editor. --- lib/screens/home.dart | 7 +- lib/selectors/recording.dart | 172 +++++++++++++++++++++++++++++ lib/widgets/ensemble_text.dart | 26 +++++ lib/widgets/performance_row.dart | 42 +++++++ lib/widgets/person_text.dart | 26 +++++ lib/widgets/works_by_composer.dart | 39 +++++++ 6 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 lib/selectors/recording.dart create mode 100644 lib/widgets/ensemble_text.dart create mode 100644 lib/widgets/performance_row.dart create mode 100644 lib/widgets/person_text.dart create mode 100644 lib/widgets/works_by_composer.dart diff --git a/lib/screens/home.dart b/lib/screens/home.dart index d583e72..d7cb9b1 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import '../backend.dart'; import '../database.dart'; -import '../editors/recording.dart'; +import '../selectors/recording.dart'; import 'person.dart'; import 'settings.dart'; @@ -25,7 +25,7 @@ class HomeScreen extends StatelessWidget { ), PopupMenuItem( value: 1, - child: Text('Add recording'), + child: Text('Select recording'), ), PopupMenuItem( value: 2, @@ -39,8 +39,7 @@ class HomeScreen extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (context) => RecordingEditor(), - fullscreenDialog: true, + builder: (context) => RecordingsSelector(), ), ); } else if (selected == 2) { diff --git a/lib/selectors/recording.dart b/lib/selectors/recording.dart new file mode 100644 index 0000000..9eba40c --- /dev/null +++ b/lib/selectors/recording.dart @@ -0,0 +1,172 @@ +import 'package:flutter/material.dart'; + +import '../backend.dart'; +import '../database.dart'; +import '../editors/recording.dart'; +import '../widgets/works_by_composer.dart'; +import '../widgets/performance_row.dart'; + +class RecordingsSelector extends StatefulWidget { + @override + _RecordingsSelectorState createState() => _RecordingsSelectorState(); +} + +class _RecordingsSelectorState extends State { + Person composer; + Work work; + + @override + Widget build(BuildContext context) { + final backend = Backend.of(context); + + bool showBackButton; + String titleText; + Widget content; + + if (composer != null) { + showBackButton = true; + if (work != null) { + titleText = work.title; + content = StreamBuilder>( + stream: backend.db.recordingsByWork(work.id).watch(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return ListView.builder( + itemCount: snapshot.data.length, + itemBuilder: (context, index) { + final recording = snapshot.data[index]; + return ListTile( + title: StreamBuilder>( + stream: backend.db + .performancesByRecording(recording.id) + .watch(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (final performance in snapshot.data) + PerformanceRow(performance), + ], + ); + } else { + return Container(); + } + }, + ), + onTap: () { + Navigator.pop(context, recording); + }, + ); + }, + ); + } else { + return Container(); + } + }, + ); + } else { + titleText = '${composer.firstName} ${composer.lastName}'; + content = WorksByComposer( + personId: composer.id, + onTap: (selectedWork) { + setState(() { + work = selectedWork; + }); + }, + ); + } + } else { + showBackButton = false; + titleText = 'Composers'; + + content = StreamBuilder>( + stream: backend.db.allPersons().watch(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return ListView.builder( + itemCount: snapshot.data.length, + itemBuilder: (context, index) { + final person = snapshot.data[index]; + return ListTile( + title: Text('${person.lastName}, ${person.firstName}'), + onTap: () { + setState(() { + composer = person; + }); + }, + ); + }, + ); + } else { + return Container(); + } + }, + ); + } + + return WillPopScope( + child: Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () => Navigator.pop(context), + ), + title: Text('Select recording'), + ), + body: Column( + children: [ + Material( + elevation: 2.0, + child: ListTile( + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: showBackButton ? goBack : null, + ), + title: Text(titleText), + ), + ), + Expanded( + child: content, + ), + ], + ), + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.add), + onPressed: () async { + final recording = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => RecordingEditor(), + fullscreenDialog: true, + ), + ); + + if (recording != null) { + Navigator.pop(context, recording); + } + }, + ), + ), + onWillPop: () => Future.value(goBack()), + ); + } + + bool goBack() { + if (work != null) { + setState(() { + work = null; + }); + + return false; + } else if (composer != null) { + setState(() { + composer = null; + }); + + return false; + } else { + return true; + } + } +} diff --git a/lib/widgets/ensemble_text.dart b/lib/widgets/ensemble_text.dart new file mode 100644 index 0000000..3882f8f --- /dev/null +++ b/lib/widgets/ensemble_text.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +import '../backend.dart'; +import '../database.dart'; + +class EnsembleText extends StatelessWidget { + final int ensembleId; + + EnsembleText(this.ensembleId); + + @override + Widget build(BuildContext context) { + final backend = Backend.of(context); + + return StreamBuilder( + stream: backend.db.ensembleById(ensembleId).watchSingle(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text(snapshot.data.name); + } else { + return Container(); + } + }, + ); + } +} diff --git a/lib/widgets/performance_row.dart b/lib/widgets/performance_row.dart new file mode 100644 index 0000000..40373dc --- /dev/null +++ b/lib/widgets/performance_row.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +import '../backend.dart'; +import '../database.dart'; + +import 'person_text.dart'; +import 'ensemble_text.dart'; + +class PerformanceRow extends StatelessWidget { + final Performance performance; + + PerformanceRow(this.performance); + + @override + Widget build(BuildContext context) { + final backend = Backend.of(context); + + return Row( + children: [ + if (performance.person != null) + PersonText(performance.person) + else if (performance.ensemble != null) + EnsembleText(performance.ensemble), + if (performance.role != null) ...[ + SizedBox( + width: 4.0, + ), + StreamBuilder( + stream: backend.db.instrumentById(performance.role).watchSingle(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text('(${snapshot.data.name})'); + } else { + return Container(); + } + }, + ), + ], + ], + ); + } +} diff --git a/lib/widgets/person_text.dart b/lib/widgets/person_text.dart new file mode 100644 index 0000000..fb14668 --- /dev/null +++ b/lib/widgets/person_text.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +import '../backend.dart'; +import '../database.dart'; + +class PersonText extends StatelessWidget { + final int personId; + + PersonText(this.personId); + + @override + Widget build(BuildContext context) { + final backend = Backend.of(context); + + return StreamBuilder( + stream: backend.db.personById(personId).watchSingle(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text('${snapshot.data.firstName} ${snapshot.data.lastName}'); + } else { + return Container(); + } + }, + ); + } +} diff --git a/lib/widgets/works_by_composer.dart b/lib/widgets/works_by_composer.dart new file mode 100644 index 0000000..0fb7a71 --- /dev/null +++ b/lib/widgets/works_by_composer.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +import '../backend.dart'; +import '../database.dart'; + +class WorksByComposer extends StatelessWidget { + final int personId; + final void Function(Work work) onTap; + + WorksByComposer({ + this.personId, + this.onTap, + }); + + @override + Widget build(BuildContext context) { + final backend = Backend.of(context); + + return StreamBuilder>( + stream: backend.db.worksByComposer(personId).watch(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return ListView.builder( + itemCount: snapshot.data.length, + itemBuilder: (context, index) { + final work = snapshot.data[index]; + return ListTile( + title: Text(work.title), + onTap: () => onTap(work), + ); + }, + ); + } else { + return Container(); + } + }, + ); + } +}