From 320028dafa39b902355ca0bfb0a770205fe034d5 Mon Sep 17 00:00:00 2001 From: Moritz Weber Date: Sat, 6 Feb 2021 14:00:04 +0100 Subject: [PATCH] some theming and persistence refactoring --- .../persistent_player_state_repository.dart | 1 + lib/presentation/pages/currently_playing.dart | 6 ++-- lib/presentation/pages/home_page.dart | 31 ++++++++++++------- lib/presentation/pages/settings_page.dart | 6 ++-- lib/presentation/state/audio_store.dart | 15 +++------ lib/presentation/state/audio_store.g.dart | 21 ++++++++----- lib/presentation/theming.dart | 2 +- .../widgets/currently_playing_bar.dart | 7 ++--- lib/presentation/widgets/header.dart | 8 ++--- lib/presentation/widgets/like_button.dart | 2 +- .../widgets/song_customization_buttons.dart | 7 ++--- .../widgets/time_progress_indicator.dart | 2 +- .../datasources/moor/player_state_dao.dart | 10 ++++++ .../datasources/player_state_data_source.dart | 2 ++ .../music_data_repository_impl.dart | 21 ++++++------- ...rsistent_player_state_repository_impl.dart | 3 ++ 16 files changed, 81 insertions(+), 63 deletions(-) diff --git a/lib/domain/repositories/persistent_player_state_repository.dart b/lib/domain/repositories/persistent_player_state_repository.dart index 6ffe81d..0df0464 100644 --- a/lib/domain/repositories/persistent_player_state_repository.dart +++ b/lib/domain/repositories/persistent_player_state_repository.dart @@ -5,6 +5,7 @@ import '../entities/song.dart'; abstract class PlayerStateRepository { Stream> get queueStream; Stream get currentIndexStream; + Stream get currentSongStream; Stream get loopModeStream; Stream get shuffleModeStream; } diff --git a/lib/presentation/pages/currently_playing.dart b/lib/presentation/pages/currently_playing.dart index 91a8af6..2b7991e 100644 --- a/lib/presentation/pages/currently_playing.dart +++ b/lib/presentation/pages/currently_playing.dart @@ -37,7 +37,7 @@ class CurrentlyPlayingPage extends StatelessWidget { child: Observer( builder: (BuildContext context) { _log.info('Observer.build'); - final Song song = audioStore.currentSong; + final Song song = audioStore.currentSongStream.value; return Stack( children: [ @@ -53,7 +53,7 @@ class CurrentlyPlayingPage extends StatelessWidget { Theme.of(context).scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor, ], - stops: [ + stops: const [ 0.0, 0.2, 0.55, @@ -102,7 +102,7 @@ class CurrentlyPlayingPage extends StatelessWidget { ), IconButton( icon: const Icon(Icons.more_vert), - onPressed: () {}, + onPressed: () => null, ) ], mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/presentation/pages/home_page.dart b/lib/presentation/pages/home_page.dart index 823411e..fcd55d9 100644 --- a/lib/presentation/pages/home_page.dart +++ b/lib/presentation/pages/home_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../theming.dart'; import '../widgets/header.dart'; import '../widgets/highlight.dart'; import '../widgets/shuffle_all_button.dart'; @@ -14,21 +15,27 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { @override Widget build(BuildContext context) { - print('HomePage.build'); return SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: Column( - children: [ - const Header(), - const Highlight(), - const ShuffleAllButton( - verticalPad: 20.0, - horizontalPad: 0.0, + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only(top: 8.0, left: HORIZONTAL_PADDING), + child: Header(), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: HORIZONTAL_PADDING), + child: Column( + children: const [ + Highlight(), + ShuffleAllButton( + verticalPad: 20.0, + horizontalPad: 0.0, + ), + ], ), - ], - ), + ), + ], ), ); } diff --git a/lib/presentation/pages/settings_page.dart b/lib/presentation/pages/settings_page.dart index 566727a..6040619 100644 --- a/lib/presentation/pages/settings_page.dart +++ b/lib/presentation/pages/settings_page.dart @@ -5,6 +5,7 @@ import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:provider/provider.dart'; import '../state/music_data_store.dart'; +import '../theming.dart'; class SettingsPage extends StatelessWidget { const SettingsPage({Key key}) : super(key: key); @@ -25,10 +26,7 @@ class SettingsPage extends StatelessWidget { ), child: Text( 'Library', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18.0, - ), + style: TEXT_HEADER, ), ), ListTile( diff --git a/lib/presentation/state/audio_store.dart b/lib/presentation/state/audio_store.dart index 48a664e..6a7d323 100644 --- a/lib/presentation/state/audio_store.dart +++ b/lib/presentation/state/audio_store.dart @@ -27,6 +27,8 @@ abstract class _AudioStore with Store { queueIndexStream = _persistentPlayerStateRepository.currentIndexStream.asObservable(); + currentSongStream = _persistentPlayerStateRepository.currentSongStream.asObservable(); + shuffleModeStream = _persistentPlayerStateRepository.shuffleModeStream.asObservable(); loopModeStream = _persistentPlayerStateRepository.loopModeStream.asObservable(); @@ -37,17 +39,8 @@ abstract class _AudioStore with Store { final AudioRepository _audioRepository; final PlayerStateRepository _persistentPlayerStateRepository; - @computed - Song get currentSong { - if (queueStream.value != null && queueIndexStream.value != null) { - if (queueIndexStream.value < queueStream.value.length) { - final song = queueStream.value[queueIndexStream.value]; - return song; - } - } - - return null; - } + @observable + ObservableStream currentSongStream; @observable ObservableStream playbackStateStream; diff --git a/lib/presentation/state/audio_store.g.dart b/lib/presentation/state/audio_store.g.dart index d6d20a8..755760a 100644 --- a/lib/presentation/state/audio_store.g.dart +++ b/lib/presentation/state/audio_store.g.dart @@ -9,13 +9,20 @@ part of 'audio_store.dart'; // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic mixin _$AudioStore on _AudioStore, Store { - Computed _$currentSongComputed; + final _$currentSongStreamAtom = Atom(name: '_AudioStore.currentSongStream'); @override - Song get currentSong => - (_$currentSongComputed ??= Computed(() => super.currentSong, - name: '_AudioStore.currentSong')) - .value; + ObservableStream get currentSongStream { + _$currentSongStreamAtom.reportRead(); + return super.currentSongStream; + } + + @override + set currentSongStream(ObservableStream value) { + _$currentSongStreamAtom.reportWrite(value, super.currentSongStream, () { + super.currentSongStream = value; + }); + } final _$playbackStateStreamAtom = Atom(name: '_AudioStore.playbackStateStream'); @@ -113,13 +120,13 @@ mixin _$AudioStore on _AudioStore, Store { @override String toString() { return ''' +currentSongStream: ${currentSongStream}, playbackStateStream: ${playbackStateStream}, currentPositionStream: ${currentPositionStream}, queueStream: ${queueStream}, queueIndexStream: ${queueIndexStream}, shuffleModeStream: ${shuffleModeStream}, -loopModeStream: ${loopModeStream}, -currentSong: ${currentSong} +loopModeStream: ${loopModeStream} '''; } } diff --git a/lib/presentation/theming.dart b/lib/presentation/theming.dart index eb9f223..bb723b2 100644 --- a/lib/presentation/theming.dart +++ b/lib/presentation/theming.dart @@ -62,7 +62,7 @@ ThemeData theme() => ThemeData( ); const TextStyle TEXT_HEADER = TextStyle( - fontSize: 18.0, + fontSize: 20.0, fontWeight: FontWeight.bold, ); diff --git a/lib/presentation/widgets/currently_playing_bar.dart b/lib/presentation/widgets/currently_playing_bar.dart index 6ca5505..b9c53f2 100644 --- a/lib/presentation/widgets/currently_playing_bar.dart +++ b/lib/presentation/widgets/currently_playing_bar.dart @@ -18,9 +18,8 @@ class CurrentlyPlayingBar extends StatelessWidget { return Observer( builder: (BuildContext context) { - if (audioStore.currentSong != null) { - final Song song = audioStore.currentSong; - + final Song song = audioStore.currentSongStream.value; + if (song != null) { return Column( verticalDirection: VerticalDirection.up, children: [ @@ -66,7 +65,7 @@ class CurrentlyPlayingBar extends StatelessWidget { ), Container( child: LinearProgressIndicator( - value: audioStore.currentPositionStream.value / audioStore.currentSong.duration, + value: audioStore.currentPositionStream.value / song.duration, valueColor: const AlwaysStoppedAnimation(Colors.white), backgroundColor: Colors.white10, ), diff --git a/lib/presentation/widgets/header.dart b/lib/presentation/widgets/header.dart index 4c5441c..e89d8f0 100644 --- a/lib/presentation/widgets/header.dart +++ b/lib/presentation/widgets/header.dart @@ -8,11 +8,11 @@ class Header extends StatelessWidget { @override Widget build(BuildContext context) { return Row( - children: const [ - Text('Home', style: TEXT_HEADER), + children: [ + const Text('Home', style: TEXT_HEADER), IconButton( - icon: Icon(Icons.more_vert), - onPressed: null, + icon: const Icon(Icons.more_vert), + onPressed: () => null, ), ], mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/presentation/widgets/like_button.dart b/lib/presentation/widgets/like_button.dart index 994be56..18adfe2 100644 --- a/lib/presentation/widgets/like_button.dart +++ b/lib/presentation/widgets/like_button.dart @@ -19,7 +19,7 @@ class LikeButton extends StatelessWidget { return Observer( builder: (BuildContext context) { - final Song song = audioStore.currentSong; + final Song song = audioStore.currentSongStream.value; if (song.likeCount == 0) { return IconButton( diff --git a/lib/presentation/widgets/song_customization_buttons.dart b/lib/presentation/widgets/song_customization_buttons.dart index f5248c3..8d7d7b4 100644 --- a/lib/presentation/widgets/song_customization_buttons.dart +++ b/lib/presentation/widgets/song_customization_buttons.dart @@ -18,8 +18,7 @@ class SongCustomizationButtons extends StatelessWidget { return Observer( builder: (BuildContext context) { print('building buttons'); - final Song song = audioStore.currentSong; - final bool isBlocked = audioStore.currentSong.blocked; + final Song song = audioStore.currentSongStream.value; return Row( children: [ IconButton( @@ -37,9 +36,9 @@ class SongCustomizationButtons extends StatelessWidget { icon: Icon( Icons.remove_circle_outline_rounded, size: 20.0, - color: isBlocked ? Colors.white : Colors.white24, + color: song.blocked ? Colors.white : Colors.white24, ), - onPressed: () => musicDataStore.setSongBlocked(song, !isBlocked), + onPressed: () => musicDataStore.setSongBlocked(song, !song.blocked), ), ], mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/presentation/widgets/time_progress_indicator.dart b/lib/presentation/widgets/time_progress_indicator.dart index 7554755..db89781 100644 --- a/lib/presentation/widgets/time_progress_indicator.dart +++ b/lib/presentation/widgets/time_progress_indicator.dart @@ -16,7 +16,7 @@ class TimeProgressIndicator extends StatelessWidget { return Observer( builder: (BuildContext context) { - final int duration = audioStore.currentSong?.duration ?? 1000; + final int duration = audioStore.currentSongStream.value?.duration ?? 1000; return Row( children: [ diff --git a/lib/system/datasources/moor/player_state_dao.dart b/lib/system/datasources/moor/player_state_dao.dart index 4eb77c8..76b27f9 100644 --- a/lib/system/datasources/moor/player_state_dao.dart +++ b/lib/system/datasources/moor/player_state_dao.dart @@ -62,6 +62,16 @@ class PlayerStateDao extends DatabaseAccessor }); } + @override + Stream get currentSongStream { + final query = select(persistentIndex).join([ + innerJoin(queueEntries, queueEntries.index.equalsExp(persistentIndex.index)), + innerJoin(songs, songs.path.equalsExp(queueEntries.path)) + ]); + + return query.watchSingle().map((row) => SongModel.fromMoor(row.readTable(songs))); + } + @override Stream get currentIndexStream { return select(persistentIndex).watchSingle().map((event) => event?.index); diff --git a/lib/system/datasources/player_state_data_source.dart b/lib/system/datasources/player_state_data_source.dart index d0672bc..80e6432 100644 --- a/lib/system/datasources/player_state_data_source.dart +++ b/lib/system/datasources/player_state_data_source.dart @@ -7,6 +7,8 @@ abstract class PlayerStateDataSource { Future setQueue(List queue); Stream> get songQueueStream; Stream> get queueStream; + + Stream get currentSongStream; Future setCurrentIndex(int index); Stream get currentIndexStream; diff --git a/lib/system/repositories/music_data_repository_impl.dart b/lib/system/repositories/music_data_repository_impl.dart index 83a6891..2d51f20 100644 --- a/lib/system/repositories/music_data_repository_impl.dart +++ b/lib/system/repositories/music_data_repository_impl.dart @@ -37,27 +37,31 @@ class MusicDataRepositoryImpl implements MusicDataRepository { Stream> getAlbumSongStream(Album album) => _musicDataSource.getAlbumSongStream(album as AlbumModel); + @override + Stream> getArtistAlbumStream(Artist artist) => + _musicDataSource.getArtistAlbumStream(artist as ArtistModel); + @override Future updateDatabase() async { _log.info('updateDatabase called'); final localMusic = await _localMusicFetcher.getLocalMusic(); - await updateArtists(localMusic['ARTISTS'] as List); - final albumIdMap = await updateAlbums(localMusic['ALBUMS'] as List); - await updateSongs(localMusic['SONGS'] as List, albumIdMap); + await _updateArtists(localMusic['ARTISTS'] as List); + final albumIdMap = await _updateAlbums(localMusic['ALBUMS'] as List); + await _updateSongs(localMusic['SONGS'] as List, albumIdMap); _log.info('updateDatabase finished'); } - Future updateArtists(List artists) async { + Future _updateArtists(List artists) async { await _musicDataSource.deleteAllArtists(); for (final ArtistModel artist in artists) { await _musicDataSource.insertArtist(artist); } } - Future> updateAlbums(List albums) async { + Future> _updateAlbums(List albums) async { await _musicDataSource.deleteAllAlbums(); final Map albumIdMap = {}; @@ -85,7 +89,7 @@ class MusicDataRepositoryImpl implements MusicDataRepository { return albumIdMap; } - Future updateSongs(List songs, Map albumIdMap) async { + Future _updateSongs(List songs, Map albumIdMap) async { final Directory dir = await getApplicationSupportDirectory(); final List songsToInsert = []; @@ -101,9 +105,4 @@ class MusicDataRepositoryImpl implements MusicDataRepository { } await _musicDataSource.insertSongs(songsToInsert); } - - @override - Stream> getArtistAlbumStream(Artist artist) { - return _musicDataSource.getArtistAlbumStream(artist as ArtistModel); - } } diff --git a/lib/system/repositories/persistent_player_state_repository_impl.dart b/lib/system/repositories/persistent_player_state_repository_impl.dart index 0ce2ca3..d030f27 100644 --- a/lib/system/repositories/persistent_player_state_repository_impl.dart +++ b/lib/system/repositories/persistent_player_state_repository_impl.dart @@ -12,6 +12,9 @@ class PlayerStateRepositoryImpl implements PlayerStateRepository { @override Stream get currentIndexStream => _playerStateDataSource.currentIndexStream; + @override + Stream get currentSongStream => _playerStateDataSource.currentSongStream; + @override Stream get loopModeStream => _playerStateDataSource.loopModeStream;