first step to loop mode implementation
This commit is contained in:
parent
9e4459bcc3
commit
f6e025c017
19 changed files with 352 additions and 21 deletions
5
lib/domain/entities/loop_mode.dart
Normal file
5
lib/domain/entities/loop_mode.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
enum LoopMode {
|
||||
off,
|
||||
one,
|
||||
all
|
||||
}
|
|
@ -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<Either<Failure, void>> skipToNext();
|
||||
Future<Either<Failure, void>> skipToPrevious();
|
||||
Future<Either<Failure, void>> setShuffleMode(ShuffleMode shuffleMode);
|
||||
|
||||
Future<void> setLoopMode(LoopMode loopMode);
|
||||
|
||||
Future<Either<Failure, void>> shuffleAll();
|
||||
Future<Either<Failure, void>> addToQueue(Song song);
|
||||
Future<Either<Failure, void>> moveQueueItem(int oldIndex, int newIndex);
|
||||
|
|
|
@ -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<List<Song>> getAlbumSongStream(Album album);
|
||||
Stream<List<Song>> get queueStream;
|
||||
Stream<int> get currentIndexStream;
|
||||
|
||||
Stream<LoopMode> get loopModeStream;
|
||||
|
||||
Future<Either<Failure, List<Song>>> getSongs();
|
||||
Future<Either<Failure, List<Song>>> getSongsFromAlbum(Album album);
|
||||
|
|
|
@ -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<ShuffleMode> shuffleModeStream;
|
||||
|
||||
@observable
|
||||
ObservableStream<LoopMode> loopModeStream;
|
||||
|
||||
@action
|
||||
Future<void> playSong(int index, List<Song> songList) async {
|
||||
_audioRepository.playSong(index, songList);
|
||||
|
@ -99,6 +105,11 @@ abstract class _AudioStore with Store {
|
|||
_audioRepository.setShuffleMode(shuffleMode);
|
||||
}
|
||||
|
||||
Future<void> setLoopMode(LoopMode loopMode) async {
|
||||
print('setLoopMode');
|
||||
_audioRepository.setLoopMode(loopMode);
|
||||
}
|
||||
|
||||
Future<void> shuffleAll() async {
|
||||
_audioRepository.shuffleAll();
|
||||
}
|
||||
|
|
|
@ -110,6 +110,21 @@ mixin _$AudioStore on _AudioStore, Store {
|
|||
});
|
||||
}
|
||||
|
||||
final _$loopModeStreamAtom = Atom(name: '_AudioStore.loopModeStream');
|
||||
|
||||
@override
|
||||
ObservableStream<LoopMode> get loopModeStream {
|
||||
_$loopModeStreamAtom.reportRead();
|
||||
return super.loopModeStream;
|
||||
}
|
||||
|
||||
@override
|
||||
set loopModeStream(ObservableStream<LoopMode> 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}
|
||||
''';
|
||||
}
|
||||
|
|
60
lib/presentation/widgets/loop_button.dart
Normal file
60
lib/presentation/widgets/loop_button.dart
Normal file
|
@ -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<AudioStore>(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();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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<void> _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<void> setCustomLoopMode(LoopMode mode) async {
|
||||
|
||||
_audioPlayer.setLoopMode(mode);
|
||||
}
|
||||
|
||||
Future<void> shuffleAll() async {
|
||||
_audioPlayer.setShuffleMode(ShuffleMode.plus, false);
|
||||
|
||||
|
|
|
@ -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<void> setLoopMode(LoopMode loopMode) async {
|
||||
print('setLoopMode!!');
|
||||
await _audioHandler.customAction(SET_LOOP_MODE, {'LOOP_MODE': loopMode});
|
||||
}
|
||||
|
||||
Stream<T> _filterStream<S, T>(Stream<S> stream, Conversion<S, T> fn) async* {
|
||||
T lastItem;
|
||||
|
||||
|
|
|
@ -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<void> skipToNext();
|
||||
Future<void> skipToPrevious();
|
||||
Future<void> setShuffleMode(ShuffleMode shuffleMode);
|
||||
Future<void> setLoopMode(LoopMode loopMode);
|
||||
Future<void> shuffleAll();
|
||||
Future<void> addToQueue(SongModel songModel);
|
||||
Future<void> moveQueueItem(int oldIndex, int newIndex);
|
||||
|
|
|
@ -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<Duration> get positionStream;
|
||||
ValueStream<List<QueueItemModel>> get queueStream;
|
||||
ValueStream<ShuffleMode> get shuffleModeStream;
|
||||
ValueStream<LoopMode> get loopModeStream;
|
||||
|
||||
Future<void> play();
|
||||
Future<void> pause();
|
||||
|
@ -28,6 +30,7 @@ abstract class AudioPlayer {
|
|||
|
||||
|
||||
Future<void> setShuffleMode(ShuffleMode shuffleMode, bool updateQueue);
|
||||
Future<void> setLoopMode(LoopMode loopMode);
|
||||
|
||||
Future<void> playSongList(List<SongModel> songs, int startIndex);
|
||||
}
|
||||
|
|
|
@ -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<Duration> _positionSubject = BehaviorSubject();
|
||||
final BehaviorSubject<List<QueueItemModel>> _queueSubject = BehaviorSubject();
|
||||
final BehaviorSubject<ShuffleMode> _shuffleModeSubject = BehaviorSubject.seeded(ShuffleMode.none);
|
||||
final BehaviorSubject<LoopMode> _loopModeSubject = BehaviorSubject();
|
||||
|
||||
@override
|
||||
ValueStream<int> get currentIndexStream => _currentIndexSubject.stream;
|
||||
|
@ -61,8 +68,18 @@ class AudioPlayerImpl implements AudioPlayer {
|
|||
@override
|
||||
ValueStream<ShuffleMode> get shuffleModeStream => _shuffleModeSubject.stream;
|
||||
|
||||
@override
|
||||
ValueStream<LoopMode> get loopModeStream => _loopModeSubject.stream;
|
||||
|
||||
@override
|
||||
Future<void> 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<void> setLoopMode(LoopMode loopMode) async {
|
||||
print('ap loopmode');
|
||||
await _audioPlayer.setLoopMode(loopMode.toJA());
|
||||
}
|
||||
|
||||
void _updateQueue(ja.ConcatenatingAudioSource newQueue, QueueItem currentQueueItem) {
|
||||
final int index = currentQueueItem.originalIndex;
|
||||
|
||||
|
|
|
@ -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';
|
|
@ -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<LoopMode> get loopModeStream {
|
||||
return select(playerState).watchSingle().map((event) => event.loopMode.toLoopMode());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> 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<void> setShuffleMode(ShuffleMode shuffleMode) {
|
||||
// TODO: implement setShuffleMode
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement shuffleModeStream
|
||||
Stream<ShuffleMode> get shuffleModeStream => throw UnimplementedError();
|
||||
}
|
||||
|
||||
LazyDatabase _openConnection() {
|
||||
|
|
|
@ -1508,7 +1508,12 @@ class $QueueEntriesTable extends QueueEntries
|
|||
class PersistentPlayerState extends DataClass
|
||||
implements Insertable<PersistentPlayerState> {
|
||||
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<String, dynamic> data, GeneratedDatabase db,
|
||||
{String prefix}) {
|
||||
|
@ -1516,6 +1521,10 @@ class PersistentPlayerState extends DataClass
|
|||
final intType = db.typeSystem.forDartType<int>();
|
||||
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<int>(index);
|
||||
}
|
||||
if (!nullToAbsent || shuffleMode != null) {
|
||||
map['shuffle_mode'] = Variable<int>(shuffleMode);
|
||||
}
|
||||
if (!nullToAbsent || loopMode != null) {
|
||||
map['loop_mode'] = Variable<int>(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<int>(json['index']),
|
||||
shuffleMode: serializer.fromJson<int>(json['shuffleMode']),
|
||||
loopMode: serializer.fromJson<int>(json['loopMode']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
|
@ -1546,47 +1569,71 @@ class PersistentPlayerState extends DataClass
|
|||
serializer ??= moorRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'index': serializer.toJson<int>(index),
|
||||
'shuffleMode': serializer.toJson<int>(shuffleMode),
|
||||
'loopMode': serializer.toJson<int>(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<PersistentPlayerState> {
|
||||
final Value<int> index;
|
||||
final Value<int> shuffleMode;
|
||||
final Value<int> 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<PersistentPlayerState> custom({
|
||||
Expression<int> index,
|
||||
Expression<int> shuffleMode,
|
||||
Expression<int> loopMode,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (index != null) 'index': index,
|
||||
if (shuffleMode != null) 'shuffle_mode': shuffleMode,
|
||||
if (loopMode != null) 'loop_mode': loopMode,
|
||||
});
|
||||
}
|
||||
|
||||
PlayerStateCompanion copyWith({Value<int> index}) {
|
||||
PlayerStateCompanion copyWith(
|
||||
{Value<int> index, Value<int> shuffleMode, Value<int> loopMode}) {
|
||||
return PlayerStateCompanion(
|
||||
index: index ?? this.index,
|
||||
shuffleMode: shuffleMode ?? this.shuffleMode,
|
||||
loopMode: loopMode ?? this.loopMode,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1596,13 +1643,21 @@ class PlayerStateCompanion extends UpdateCompanion<PersistentPlayerState> {
|
|||
if (index.present) {
|
||||
map['index'] = Variable<int>(index.value);
|
||||
}
|
||||
if (shuffleMode.present) {
|
||||
map['shuffle_mode'] = Variable<int>(shuffleMode.value);
|
||||
}
|
||||
if (loopMode.present) {
|
||||
map['loop_mode'] = Variable<int>(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<GeneratedColumn> 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<GeneratedColumn> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<List<QueueItemModel>> get queueStream;
|
||||
Future<void> setCurrentIndex(int index);
|
||||
Stream<int> get currentIndexStream;
|
||||
Future<void> setShuffleMode(ShuffleMode shuffleMode);
|
||||
Stream<ShuffleMode> get shuffleModeStream;
|
||||
Future<void> setLoopMode(LoopMode loopMode);
|
||||
Stream<LoopMode> get loopModeStream;
|
||||
|
||||
/// Insert album into the database. Return the ID of the inserted album.
|
||||
Future<int> insertAlbum(AlbumModel albumModel);
|
||||
|
|
55
lib/system/models/loop_mode_model.dart
Normal file
55
lib/system/models/loop_mode_model.dart
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<void> setLoopMode(LoopMode loopMode) async {
|
||||
print('setLoopMode!');
|
||||
await _audioManager.setLoopMode(loopMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<int> get currentIndexStream => musicDataSource.currentIndexStream;
|
||||
|
||||
@override
|
||||
Stream<LoopMode> get loopModeStream => musicDataSource.loopModeStream;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue