From f6e025c017f28044e73435ec6d4c207a187d037d Mon Sep 17 00:00:00 2001 From: Moritz Weber Date: Sat, 19 Dec 2020 12:22:57 +0100 Subject: [PATCH] first step to loop mode implementation --- lib/domain/entities/loop_mode.dart | 5 + lib/domain/repositories/audio_repository.dart | 4 + .../repositories/music_data_repository.dart | 3 + lib/presentation/state/audio_store.dart | 13 ++- lib/presentation/state/audio_store.g.dart | 16 +++ lib/presentation/widgets/loop_button.dart | 60 +++++++++++ .../widgets/playback_control.dart | 10 +- lib/system/audio/audio_handler.dart | 22 +++- lib/system/audio/audio_manager.dart | 7 ++ lib/system/audio/audio_manager_contract.dart | 2 + lib/system/audio/audio_player_contract.dart | 3 + lib/system/audio/audio_player_impl.dart | 23 ++++ lib/system/audio/stream_constants.dart | 1 + .../datasources/moor_music_data_source.dart | 31 ++++++ .../datasources/moor_music_data_source.g.dart | 101 ++++++++++++++++-- .../music_data_source_contract.dart | 6 ++ lib/system/models/loop_mode_model.dart | 55 ++++++++++ .../repositories/audio_repository_impl.dart | 7 ++ .../music_data_repository_impl.dart | 4 + 19 files changed, 352 insertions(+), 21 deletions(-) create mode 100644 lib/domain/entities/loop_mode.dart create mode 100644 lib/presentation/widgets/loop_button.dart create mode 100644 lib/system/models/loop_mode_model.dart diff --git a/lib/domain/entities/loop_mode.dart b/lib/domain/entities/loop_mode.dart new file mode 100644 index 0000000..a9ac06c --- /dev/null +++ b/lib/domain/entities/loop_mode.dart @@ -0,0 +1,5 @@ +enum LoopMode { + off, + one, + all +} \ No newline at end of file diff --git a/lib/domain/repositories/audio_repository.dart b/lib/domain/repositories/audio_repository.dart index 8a30192..b217502 100644 --- a/lib/domain/repositories/audio_repository.dart +++ b/lib/domain/repositories/audio_repository.dart @@ -1,6 +1,7 @@ import 'package:dartz/dartz.dart'; import '../../core/error/failures.dart'; +import '../entities/loop_mode.dart'; import '../entities/playback_state.dart'; import '../entities/shuffle_mode.dart'; import '../entities/song.dart'; @@ -19,6 +20,9 @@ abstract class AudioRepository { Future> skipToNext(); Future> skipToPrevious(); Future> setShuffleMode(ShuffleMode shuffleMode); + + Future setLoopMode(LoopMode loopMode); + Future> shuffleAll(); Future> addToQueue(Song song); Future> moveQueueItem(int oldIndex, int newIndex); diff --git a/lib/domain/repositories/music_data_repository.dart b/lib/domain/repositories/music_data_repository.dart index 8834c06..33ed718 100644 --- a/lib/domain/repositories/music_data_repository.dart +++ b/lib/domain/repositories/music_data_repository.dart @@ -3,6 +3,7 @@ import 'package:dartz/dartz.dart'; import '../../core/error/failures.dart'; import '../entities/album.dart'; import '../entities/artist.dart'; +import '../entities/loop_mode.dart'; import '../entities/song.dart'; abstract class MusicDataRepository { @@ -10,6 +11,8 @@ abstract class MusicDataRepository { Stream> getAlbumSongStream(Album album); Stream> get queueStream; Stream get currentIndexStream; + + Stream get loopModeStream; Future>> getSongs(); Future>> getSongsFromAlbum(Album album); diff --git a/lib/presentation/state/audio_store.dart b/lib/presentation/state/audio_store.dart index c79ece8..1e3668c 100644 --- a/lib/presentation/state/audio_store.dart +++ b/lib/presentation/state/audio_store.dart @@ -1,11 +1,12 @@ import 'package:meta/meta.dart'; import 'package:mobx/mobx.dart'; -import 'package:mucke/domain/repositories/music_data_repository.dart'; +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/playback_state.dart'; import '../../domain/entities/shuffle_mode.dart'; import '../../domain/entities/song.dart'; import '../../domain/repositories/audio_repository.dart'; +import '../../domain/repositories/music_data_repository.dart'; part 'audio_store.g.dart'; @@ -30,6 +31,8 @@ abstract class _AudioStore with Store { shuffleModeStream = _audioRepository.shuffleModeStream.asObservable(initialValue: ShuffleMode.none); + loopModeStream = _musicDataRepository.loopModeStream.asObservable(); + playbackStateStream = _audioRepository.playbackStateStream.asObservable(); } @@ -70,6 +73,9 @@ abstract class _AudioStore with Store { @observable ObservableStream shuffleModeStream; + @observable + ObservableStream loopModeStream; + @action Future playSong(int index, List songList) async { _audioRepository.playSong(index, songList); @@ -99,6 +105,11 @@ abstract class _AudioStore with Store { _audioRepository.setShuffleMode(shuffleMode); } + Future setLoopMode(LoopMode loopMode) async { + print('setLoopMode'); + _audioRepository.setLoopMode(loopMode); + } + Future shuffleAll() async { _audioRepository.shuffleAll(); } diff --git a/lib/presentation/state/audio_store.g.dart b/lib/presentation/state/audio_store.g.dart index 01f8c21..76bb378 100644 --- a/lib/presentation/state/audio_store.g.dart +++ b/lib/presentation/state/audio_store.g.dart @@ -110,6 +110,21 @@ mixin _$AudioStore on _AudioStore, Store { }); } + final _$loopModeStreamAtom = Atom(name: '_AudioStore.loopModeStream'); + + @override + ObservableStream get loopModeStream { + _$loopModeStreamAtom.reportRead(); + return super.loopModeStream; + } + + @override + set loopModeStream(ObservableStream value) { + _$loopModeStreamAtom.reportWrite(value, super.loopModeStream, () { + super.loopModeStream = value; + }); + } + final _$playSongAsyncAction = AsyncAction('_AudioStore.playSong'); @override @@ -154,6 +169,7 @@ currentPositionStream: ${currentPositionStream}, queueStream: ${queueStream}, queueIndexStream: ${queueIndexStream}, shuffleModeStream: ${shuffleModeStream}, +loopModeStream: ${loopModeStream}, currentSong: ${currentSong} '''; } diff --git a/lib/presentation/widgets/loop_button.dart b/lib/presentation/widgets/loop_button.dart new file mode 100644 index 0000000..0dfb07a --- /dev/null +++ b/lib/presentation/widgets/loop_button.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:provider/provider.dart'; + +import '../../domain/entities/loop_mode.dart'; +import '../state/audio_store.dart'; + +class LoopButton extends StatelessWidget { + const LoopButton({Key key, this.iconSize = 20.0}) : super(key: key); + + final double iconSize; + + @override + Widget build(BuildContext context) { + final AudioStore audioStore = Provider.of(context); + + return Observer( + builder: (BuildContext context) { + if (audioStore.loopModeStream != null) { + switch (audioStore.loopModeStream.value) { + case LoopMode.off: + return IconButton( + icon: const Icon( + Icons.repeat_rounded, + color: Colors.white30, + ), + iconSize: iconSize, + onPressed: () { + audioStore.setLoopMode(LoopMode.all); + }, + ); + case LoopMode.one: + return IconButton( + icon: const Icon( + Icons.repeat_one_rounded, + color: Colors.white, + ), + iconSize: iconSize, + onPressed: () { + audioStore.setLoopMode(LoopMode.off); + }, + ); + case LoopMode.all: + return IconButton( + icon: const Icon( + Icons.repeat_rounded, + color: Colors.white, + ), + iconSize: iconSize, + onPressed: () { + audioStore.setLoopMode(LoopMode.one); + }, + ); + } + } + return Container(); + }, + ); + } +} diff --git a/lib/presentation/widgets/playback_control.dart b/lib/presentation/widgets/playback_control.dart index 479a495..38fb5d6 100644 --- a/lib/presentation/widgets/playback_control.dart +++ b/lib/presentation/widgets/playback_control.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'loop_button.dart'; import 'next_button.dart'; import 'play_pause_button.dart'; import 'previous_button.dart'; @@ -12,14 +13,7 @@ class PlaybackControl extends StatelessWidget { Widget build(BuildContext context) { return Row( children: const [ - IconButton( - icon: Icon( - Icons.repeat, - size: 20.0, - color: Colors.white10, - ), - onPressed: null, - ), + LoopButton(iconSize: 20.0), PreviousButton(iconSize: 32.0), PlayPauseButton( circle: true, diff --git a/lib/system/audio/audio_handler.dart b/lib/system/audio/audio_handler.dart index b705034..6ca2471 100644 --- a/lib/system/audio/audio_handler.dart +++ b/lib/system/audio/audio_handler.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:audio_service/audio_service.dart'; import 'package:logging/logging.dart'; +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/player_state.dart'; import '../../domain/entities/shuffle_mode.dart'; import '../datasources/music_data_source_contract.dart'; @@ -31,14 +32,20 @@ class MyAudioHandler extends BaseAudioHandler { customEventSubject.add({SHUFFLE_MODE: shuffleMode}); }); + _audioPlayer.loopModeStream.listen((event) { + _musicDataSource.setLoopMode(event); + }); + _initAudioPlayer(); } Future _initAudioPlayer() async { - _audioPlayer.loadQueue( - queue: await _musicDataSource.queueStream.first, - startIndex: await _musicDataSource.currentIndexStream.first, - ); + if (_musicDataSource.queueStream != null && _musicDataSource.currentIndexStream != null) { + _audioPlayer.loadQueue( + queue: await _musicDataSource.queueStream.first, + startIndex: await _musicDataSource.currentIndexStream.first, + ); + } } final AudioPlayer _audioPlayer; @@ -89,6 +96,8 @@ class MyAudioHandler extends BaseAudioHandler { return onAppLifecycleResumed(); case SET_SHUFFLE_MODE: return setCustomShuffleMode(arguments['SHUFFLE_MODE'] as ShuffleMode); + case SET_LOOP_MODE: + return setCustomLoopMode(arguments['LOOP_MODE'] as LoopMode); case SHUFFLE_ALL: return shuffleAll(); case MOVE_QUEUE_ITEM: @@ -118,6 +127,11 @@ class MyAudioHandler extends BaseAudioHandler { _audioPlayer.setShuffleMode(mode, true); } + Future setCustomLoopMode(LoopMode mode) async { + + _audioPlayer.setLoopMode(mode); + } + Future shuffleAll() async { _audioPlayer.setShuffleMode(ShuffleMode.plus, false); diff --git a/lib/system/audio/audio_manager.dart b/lib/system/audio/audio_manager.dart index ff80d9e..d8f2068 100644 --- a/lib/system/audio/audio_manager.dart +++ b/lib/system/audio/audio_manager.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:audio_service/audio_service.dart'; +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/playback_state.dart' as entity; import '../../domain/entities/shuffle_mode.dart'; import '../models/playback_state_model.dart'; @@ -115,6 +116,12 @@ class AudioManagerImpl implements AudioManager { await _audioHandler.customAction(SET_SHUFFLE_MODE, {'SHUFFLE_MODE': shuffleMode}); } + @override + Future setLoopMode(LoopMode loopMode) async { + print('setLoopMode!!'); + await _audioHandler.customAction(SET_LOOP_MODE, {'LOOP_MODE': loopMode}); + } + Stream _filterStream(Stream stream, Conversion fn) async* { T lastItem; diff --git a/lib/system/audio/audio_manager_contract.dart b/lib/system/audio/audio_manager_contract.dart index ce18213..40c6c6b 100644 --- a/lib/system/audio/audio_manager_contract.dart +++ b/lib/system/audio/audio_manager_contract.dart @@ -1,3 +1,4 @@ +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/playback_state.dart'; import '../../domain/entities/shuffle_mode.dart'; import '../models/song_model.dart'; @@ -17,6 +18,7 @@ abstract class AudioManager { Future skipToNext(); Future skipToPrevious(); Future setShuffleMode(ShuffleMode shuffleMode); + Future setLoopMode(LoopMode loopMode); Future shuffleAll(); Future addToQueue(SongModel songModel); Future moveQueueItem(int oldIndex, int newIndex); diff --git a/lib/system/audio/audio_player_contract.dart b/lib/system/audio/audio_player_contract.dart index 47915c4..bd2f945 100644 --- a/lib/system/audio/audio_player_contract.dart +++ b/lib/system/audio/audio_player_contract.dart @@ -1,5 +1,6 @@ import 'package:rxdart/rxdart.dart'; +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/shuffle_mode.dart'; import '../models/player_state_model.dart'; import '../models/queue_item_model.dart'; @@ -12,6 +13,7 @@ abstract class AudioPlayer { ValueStream get positionStream; ValueStream> get queueStream; ValueStream get shuffleModeStream; + ValueStream get loopModeStream; Future play(); Future pause(); @@ -28,6 +30,7 @@ abstract class AudioPlayer { Future setShuffleMode(ShuffleMode shuffleMode, bool updateQueue); + Future setLoopMode(LoopMode loopMode); Future playSongList(List songs, int startIndex); } diff --git a/lib/system/audio/audio_player_impl.dart b/lib/system/audio/audio_player_impl.dart index 3eb018b..3138a6d 100644 --- a/lib/system/audio/audio_player_impl.dart +++ b/lib/system/audio/audio_player_impl.dart @@ -1,8 +1,10 @@ import 'package:just_audio/just_audio.dart' as ja; import 'package:rxdart/rxdart.dart'; +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/queue_item.dart'; import '../../domain/entities/shuffle_mode.dart'; +import '../models/loop_mode_model.dart'; import '../models/player_state_model.dart'; import '../models/queue_item_model.dart'; import '../models/song_model.dart'; @@ -24,6 +26,10 @@ class AudioPlayerImpl implements AudioPlayer { _playerStateSubject.add(PlayerStateModel.fromJAPlayerState(event)); }); + _audioPlayer.loopModeStream.listen((event) { + _loopModeSubject.add(event.toEntity()); + }); + _queueSubject.listen((event) { _currentSongSubject.add(event[_currentIndexSubject.value].song); }); @@ -42,6 +48,7 @@ class AudioPlayerImpl implements AudioPlayer { final BehaviorSubject _positionSubject = BehaviorSubject(); final BehaviorSubject> _queueSubject = BehaviorSubject(); final BehaviorSubject _shuffleModeSubject = BehaviorSubject.seeded(ShuffleMode.none); + final BehaviorSubject _loopModeSubject = BehaviorSubject(); @override ValueStream get currentIndexStream => _currentIndexSubject.stream; @@ -61,8 +68,18 @@ class AudioPlayerImpl implements AudioPlayer { @override ValueStream get shuffleModeStream => _shuffleModeSubject.stream; + @override + ValueStream get loopModeStream => _loopModeSubject.stream; + @override Future dispose() async { + await _currentIndexSubject.close(); + await _currentSongSubject.close(); + await _playerStateSubject.close(); + await _positionSubject.close(); + await _queueSubject.close(); + await _shuffleModeSubject.close(); + await _loopModeSubject.close(); await _audioPlayer.dispose(); } @@ -174,6 +191,12 @@ class AudioPlayerImpl implements AudioPlayer { } } + @override + Future setLoopMode(LoopMode loopMode) async { + print('ap loopmode'); + await _audioPlayer.setLoopMode(loopMode.toJA()); + } + void _updateQueue(ja.ConcatenatingAudioSource newQueue, QueueItem currentQueueItem) { final int index = currentQueueItem.originalIndex; diff --git a/lib/system/audio/stream_constants.dart b/lib/system/audio/stream_constants.dart index 5d54f35..8f81a43 100644 --- a/lib/system/audio/stream_constants.dart +++ b/lib/system/audio/stream_constants.dart @@ -5,5 +5,6 @@ const String PLAY_WITH_CONTEXT = 'PLAY_WITH_CONTEXT'; const String APP_LIFECYCLE_RESUMED = 'APP_LIFECYCLE_RESUMED'; const String SHUFFLE_ALL = 'SHUFFLE_ALL'; const String SET_SHUFFLE_MODE = 'SET_SHUFFLE_MODE'; +const String SET_LOOP_MODE = 'SET_LOOP_MODE'; const String MOVE_QUEUE_ITEM = 'MOVE_QUEUE_ITEM'; const String REMOVE_QUEUE_ITEM = 'REMOVE_QUEUE_ITEM'; \ No newline at end of file diff --git a/lib/system/datasources/moor_music_data_source.dart b/lib/system/datasources/moor_music_data_source.dart index 2c585b7..cf4c0e3 100644 --- a/lib/system/datasources/moor_music_data_source.dart +++ b/lib/system/datasources/moor_music_data_source.dart @@ -7,8 +7,11 @@ import 'package:moor/moor.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; +import '../../domain/entities/loop_mode.dart'; +import '../../domain/entities/shuffle_mode.dart'; import '../models/album_model.dart'; import '../models/artist_model.dart'; +import '../models/loop_mode_model.dart'; import '../models/queue_item_model.dart'; import '../models/song_model.dart'; import 'music_data_source_contract.dart'; @@ -69,6 +72,8 @@ class QueueEntries extends Table { @DataClassName('PersistentPlayerState') class PlayerState extends Table { IntColumn get index => integer()(); + IntColumn get shuffleMode => integer().withDefault(const Constant(0))(); + IntColumn get loopMode => integer().withDefault(const Constant(0))(); } @UseMoor(tables: [Artists, Albums, Songs, QueueEntries, PlayerState]) @@ -293,6 +298,32 @@ class MoorMusicDataSource extends _$MoorMusicDataSource implements MusicDataSour into(playerState).insert(PlayerStateCompanion(index: Value(index))); } } + + @override + Stream get loopModeStream { + return select(playerState).watchSingle().map((event) => event.loopMode.toLoopMode()); + } + + @override + Future setLoopMode(LoopMode loopMode) async { + print('setLoopMode!!!'); + final currentState = await select(playerState).getSingle(); + if (currentState != null) { + update(playerState).write(PlayerStateCompanion(loopMode: Value(loopMode.toInt()))); + } else { + into(playerState).insert(PlayerStateCompanion(loopMode: Value(loopMode.toInt()))); + } + } + + @override + Future setShuffleMode(ShuffleMode shuffleMode) { + // TODO: implement setShuffleMode + throw UnimplementedError(); + } + + @override + // TODO: implement shuffleModeStream + Stream get shuffleModeStream => throw UnimplementedError(); } LazyDatabase _openConnection() { diff --git a/lib/system/datasources/moor_music_data_source.g.dart b/lib/system/datasources/moor_music_data_source.g.dart index 8d8dcf5..97c2c73 100644 --- a/lib/system/datasources/moor_music_data_source.g.dart +++ b/lib/system/datasources/moor_music_data_source.g.dart @@ -1508,7 +1508,12 @@ class $QueueEntriesTable extends QueueEntries class PersistentPlayerState extends DataClass implements Insertable { final int index; - PersistentPlayerState({@required this.index}); + final int shuffleMode; + final int loopMode; + PersistentPlayerState( + {@required this.index, + @required this.shuffleMode, + @required this.loopMode}); factory PersistentPlayerState.fromData( Map data, GeneratedDatabase db, {String prefix}) { @@ -1516,6 +1521,10 @@ class PersistentPlayerState extends DataClass final intType = db.typeSystem.forDartType(); return PersistentPlayerState( index: intType.mapFromDatabaseResponse(data['${effectivePrefix}index']), + shuffleMode: intType + .mapFromDatabaseResponse(data['${effectivePrefix}shuffle_mode']), + loopMode: + intType.mapFromDatabaseResponse(data['${effectivePrefix}loop_mode']), ); } @override @@ -1524,6 +1533,12 @@ class PersistentPlayerState extends DataClass if (!nullToAbsent || index != null) { map['index'] = Variable(index); } + if (!nullToAbsent || shuffleMode != null) { + map['shuffle_mode'] = Variable(shuffleMode); + } + if (!nullToAbsent || loopMode != null) { + map['loop_mode'] = Variable(loopMode); + } return map; } @@ -1531,6 +1546,12 @@ class PersistentPlayerState extends DataClass return PlayerStateCompanion( index: index == null && nullToAbsent ? const Value.absent() : Value(index), + shuffleMode: shuffleMode == null && nullToAbsent + ? const Value.absent() + : Value(shuffleMode), + loopMode: loopMode == null && nullToAbsent + ? const Value.absent() + : Value(loopMode), ); } @@ -1539,6 +1560,8 @@ class PersistentPlayerState extends DataClass serializer ??= moorRuntimeOptions.defaultSerializer; return PersistentPlayerState( index: serializer.fromJson(json['index']), + shuffleMode: serializer.fromJson(json['shuffleMode']), + loopMode: serializer.fromJson(json['loopMode']), ); } @override @@ -1546,47 +1569,71 @@ class PersistentPlayerState extends DataClass serializer ??= moorRuntimeOptions.defaultSerializer; return { 'index': serializer.toJson(index), + 'shuffleMode': serializer.toJson(shuffleMode), + 'loopMode': serializer.toJson(loopMode), }; } - PersistentPlayerState copyWith({int index}) => PersistentPlayerState( + PersistentPlayerState copyWith({int index, int shuffleMode, int loopMode}) => + PersistentPlayerState( index: index ?? this.index, + shuffleMode: shuffleMode ?? this.shuffleMode, + loopMode: loopMode ?? this.loopMode, ); @override String toString() { return (StringBuffer('PersistentPlayerState(') - ..write('index: $index') + ..write('index: $index, ') + ..write('shuffleMode: $shuffleMode, ') + ..write('loopMode: $loopMode') ..write(')')) .toString(); } @override - int get hashCode => $mrjf(index.hashCode); + int get hashCode => $mrjf( + $mrjc(index.hashCode, $mrjc(shuffleMode.hashCode, loopMode.hashCode))); @override bool operator ==(dynamic other) => identical(this, other) || - (other is PersistentPlayerState && other.index == this.index); + (other is PersistentPlayerState && + other.index == this.index && + other.shuffleMode == this.shuffleMode && + other.loopMode == this.loopMode); } class PlayerStateCompanion extends UpdateCompanion { final Value index; + final Value shuffleMode; + final Value loopMode; const PlayerStateCompanion({ this.index = const Value.absent(), + this.shuffleMode = const Value.absent(), + this.loopMode = const Value.absent(), }); PlayerStateCompanion.insert({ @required int index, + this.shuffleMode = const Value.absent(), + this.loopMode = const Value.absent(), }) : index = Value(index); static Insertable custom({ Expression index, + Expression shuffleMode, + Expression loopMode, }) { return RawValuesInsertable({ if (index != null) 'index': index, + if (shuffleMode != null) 'shuffle_mode': shuffleMode, + if (loopMode != null) 'loop_mode': loopMode, }); } - PlayerStateCompanion copyWith({Value index}) { + PlayerStateCompanion copyWith( + {Value index, Value shuffleMode, Value loopMode}) { return PlayerStateCompanion( index: index ?? this.index, + shuffleMode: shuffleMode ?? this.shuffleMode, + loopMode: loopMode ?? this.loopMode, ); } @@ -1596,13 +1643,21 @@ class PlayerStateCompanion extends UpdateCompanion { if (index.present) { map['index'] = Variable(index.value); } + if (shuffleMode.present) { + map['shuffle_mode'] = Variable(shuffleMode.value); + } + if (loopMode.present) { + map['loop_mode'] = Variable(loopMode.value); + } return map; } @override String toString() { return (StringBuffer('PlayerStateCompanion(') - ..write('index: $index') + ..write('index: $index, ') + ..write('shuffleMode: $shuffleMode, ') + ..write('loopMode: $loopMode') ..write(')')) .toString(); } @@ -1625,8 +1680,28 @@ class $PlayerStateTable extends PlayerState ); } + final VerificationMeta _shuffleModeMeta = + const VerificationMeta('shuffleMode'); + GeneratedIntColumn _shuffleMode; @override - List get $columns => [index]; + GeneratedIntColumn get shuffleMode => + _shuffleMode ??= _constructShuffleMode(); + GeneratedIntColumn _constructShuffleMode() { + return GeneratedIntColumn('shuffle_mode', $tableName, false, + defaultValue: const Constant(0)); + } + + final VerificationMeta _loopModeMeta = const VerificationMeta('loopMode'); + GeneratedIntColumn _loopMode; + @override + GeneratedIntColumn get loopMode => _loopMode ??= _constructLoopMode(); + GeneratedIntColumn _constructLoopMode() { + return GeneratedIntColumn('loop_mode', $tableName, false, + defaultValue: const Constant(0)); + } + + @override + List get $columns => [index, shuffleMode, loopMode]; @override $PlayerStateTable get asDslTable => this; @override @@ -1645,6 +1720,16 @@ class $PlayerStateTable extends PlayerState } else if (isInserting) { context.missing(_indexMeta); } + if (data.containsKey('shuffle_mode')) { + context.handle( + _shuffleModeMeta, + shuffleMode.isAcceptableOrUnknown( + data['shuffle_mode'], _shuffleModeMeta)); + } + if (data.containsKey('loop_mode')) { + context.handle(_loopModeMeta, + loopMode.isAcceptableOrUnknown(data['loop_mode'], _loopModeMeta)); + } return context; } diff --git a/lib/system/datasources/music_data_source_contract.dart b/lib/system/datasources/music_data_source_contract.dart index 65e6a89..44288b9 100644 --- a/lib/system/datasources/music_data_source_contract.dart +++ b/lib/system/datasources/music_data_source_contract.dart @@ -1,3 +1,5 @@ +import '../../domain/entities/loop_mode.dart'; +import '../../domain/entities/shuffle_mode.dart'; import '../models/album_model.dart'; import '../models/artist_model.dart'; import '../models/queue_item_model.dart'; @@ -14,6 +16,10 @@ abstract class MusicDataSource { Stream> get queueStream; Future setCurrentIndex(int index); Stream get currentIndexStream; + Future setShuffleMode(ShuffleMode shuffleMode); + Stream get shuffleModeStream; + Future setLoopMode(LoopMode loopMode); + Stream get loopModeStream; /// Insert album into the database. Return the ID of the inserted album. Future insertAlbum(AlbumModel albumModel); diff --git a/lib/system/models/loop_mode_model.dart b/lib/system/models/loop_mode_model.dart new file mode 100644 index 0000000..0886a50 --- /dev/null +++ b/lib/system/models/loop_mode_model.dart @@ -0,0 +1,55 @@ +import 'package:just_audio/just_audio.dart' as ja; + +import '../../domain/entities/loop_mode.dart'; + +extension LoopModeToJA on LoopMode { + ja.LoopMode toJA() { + switch(this) { + case LoopMode.one: + return ja.LoopMode.one; + case LoopMode.all: + return ja.LoopMode.all; + default: + return ja.LoopMode.off; + } + } +} + +extension JALoopModeToEntity on ja.LoopMode { + LoopMode toEntity() { + switch(this) { + case ja.LoopMode.one: + return LoopMode.one; + case ja.LoopMode.all: + return LoopMode.all; + default: + return LoopMode.off; + } + } +} + +extension LoopModeToInt on LoopMode { + int toInt() { + switch(this) { + case LoopMode.one: + return 1; + case LoopMode.all: + return 2; + default: + return 0; + } + } +} + +extension IntToLoopMode on int { + LoopMode toLoopMode() { + switch(this) { + case 1: + return LoopMode.one; + case 2: + return LoopMode.all; + default: + return LoopMode.off; + } + } +} \ No newline at end of file diff --git a/lib/system/repositories/audio_repository_impl.dart b/lib/system/repositories/audio_repository_impl.dart index d7bab9f..cf31796 100644 --- a/lib/system/repositories/audio_repository_impl.dart +++ b/lib/system/repositories/audio_repository_impl.dart @@ -1,6 +1,7 @@ import 'package:dartz/dartz.dart'; import '../../core/error/failures.dart'; +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/playback_state.dart'; import '../../domain/entities/shuffle_mode.dart'; import '../../domain/entities/song.dart'; @@ -97,4 +98,10 @@ class AudioRepositoryImpl implements AudioRepository { await _audioManager.removeQueueIndex(index); return const Right(null); } + + @override + Future setLoopMode(LoopMode loopMode) async { + print('setLoopMode!'); + await _audioManager.setLoopMode(loopMode); + } } diff --git a/lib/system/repositories/music_data_repository_impl.dart b/lib/system/repositories/music_data_repository_impl.dart index 9ef4474..5928cd3 100644 --- a/lib/system/repositories/music_data_repository_impl.dart +++ b/lib/system/repositories/music_data_repository_impl.dart @@ -8,6 +8,7 @@ import 'package:path_provider/path_provider.dart'; import '../../core/error/failures.dart'; import '../../domain/entities/album.dart'; import '../../domain/entities/artist.dart'; +import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/song.dart'; import '../../domain/repositories/music_data_repository.dart'; import '../datasources/local_music_fetcher_contract.dart'; @@ -139,4 +140,7 @@ class MusicDataRepositoryImpl implements MusicDataRepository { @override Stream get currentIndexStream => musicDataSource.currentIndexStream; + + @override + Stream get loopModeStream => musicDataSource.loopModeStream; }