queue and audiosource stuff
This commit is contained in:
parent
39e4111037
commit
5c6a8a0a6d
19 changed files with 629 additions and 221 deletions
|
@ -3,30 +3,104 @@ import '../entities/shuffle_mode.dart';
|
||||||
import '../entities/song.dart';
|
import '../entities/song.dart';
|
||||||
import '../repositories/music_data_repository.dart';
|
import '../repositories/music_data_repository.dart';
|
||||||
|
|
||||||
class QueueGenerationModule {
|
class QueueManagerModule {
|
||||||
QueueGenerationModule(this._musicDataRepository);
|
QueueManagerModule(this._musicDataRepository);
|
||||||
|
|
||||||
|
List<QueueItem> get queue => _queue;
|
||||||
|
|
||||||
final MusicDataInfoRepository _musicDataRepository;
|
final MusicDataInfoRepository _musicDataRepository;
|
||||||
|
|
||||||
Future<List<QueueItem>> generateQueue(
|
List<Song> _originalSongList = [];
|
||||||
|
List<Song> _addedSongs = [];
|
||||||
|
// this resembles the queue in AudioPlayer
|
||||||
|
List<QueueItem> _queue;
|
||||||
|
|
||||||
|
void addToQueue(Song song) {
|
||||||
|
_addedSongs.add(song);
|
||||||
|
final queueItem = QueueItem(
|
||||||
|
song,
|
||||||
|
originalIndex: _addedSongs.length - 1,
|
||||||
|
type: QueueItemType.added,
|
||||||
|
);
|
||||||
|
_queue.add(queueItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertIntoQueue(Song song, int index) {
|
||||||
|
_addedSongs.add(song);
|
||||||
|
final queueItem = QueueItem(
|
||||||
|
song,
|
||||||
|
originalIndex: _addedSongs.length - 1,
|
||||||
|
type: QueueItemType.added,
|
||||||
|
);
|
||||||
|
_queue.insert(index, queueItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveQueueItem(int oldIndex, int newIndex) {
|
||||||
|
final queueItem = _queue.removeAt(oldIndex);
|
||||||
|
_queue.insert(newIndex, queueItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeQueueIndex(int index) {
|
||||||
|
final queueItem = _queue[index];
|
||||||
|
|
||||||
|
if (queueItem.type == QueueItemType.added) {
|
||||||
|
_addedSongs.removeAt(queueItem.originalIndex);
|
||||||
|
} else if (queueItem.type == QueueItemType.standard) {
|
||||||
|
_originalSongList.removeAt(queueItem.originalIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < queue.length; i++) {
|
||||||
|
if (queue[i].type == queueItem.type && queue[i].originalIndex > queueItem.originalIndex) {
|
||||||
|
queue[i] = QueueItem(
|
||||||
|
queue[i].song,
|
||||||
|
originalIndex: queue[i].originalIndex - 1,
|
||||||
|
type: queue[i].type,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_queue.removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> reshuffleQueue(
|
||||||
|
ShuffleMode shuffleMode,
|
||||||
|
int currentIndex,
|
||||||
|
) async {
|
||||||
|
final songs = _originalSongList.cast<Song>() + _addedSongs;
|
||||||
|
final currentQueueItem = _queue[currentIndex];
|
||||||
|
int originalIndex = currentQueueItem.originalIndex;
|
||||||
|
if (currentQueueItem.type == QueueItemType.added) {
|
||||||
|
originalIndex += _originalSongList.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
_queue = await _generateQueue(shuffleMode, songs, originalIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setQueue(
|
||||||
ShuffleMode shuffleMode,
|
ShuffleMode shuffleMode,
|
||||||
List<Song> songs,
|
List<Song> songs,
|
||||||
int startIndex,
|
int startIndex,
|
||||||
) async {
|
) async {
|
||||||
List<QueueItem> queue;
|
_originalSongList = songs;
|
||||||
|
_addedSongs = [];
|
||||||
|
|
||||||
|
_queue = await _generateQueue(shuffleMode, songs, startIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore: missing_return
|
||||||
|
Future<List<QueueItem>> _generateQueue(
|
||||||
|
ShuffleMode shuffleMode,
|
||||||
|
List<Song> songs,
|
||||||
|
int startIndex,
|
||||||
|
) async {
|
||||||
switch (shuffleMode) {
|
switch (shuffleMode) {
|
||||||
case ShuffleMode.none:
|
case ShuffleMode.none:
|
||||||
queue = _generateNormalQueue(songs);
|
return _generateNormalQueue(songs);
|
||||||
break;
|
|
||||||
case ShuffleMode.standard:
|
case ShuffleMode.standard:
|
||||||
queue = _generateShuffleQueue(songs, startIndex);
|
return _generateShuffleQueue(songs, startIndex);
|
||||||
break;
|
|
||||||
case ShuffleMode.plus:
|
case ShuffleMode.plus:
|
||||||
queue = await _generateShufflePlusQueue(songs, startIndex);
|
return await _generateShufflePlusQueue(songs, startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return queue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<QueueItem> _generateNormalQueue(List<Song> songs) {
|
List<QueueItem> _generateNormalQueue(List<Song> songs) {
|
|
@ -3,7 +3,6 @@ import 'package:rxdart/rxdart.dart';
|
||||||
import '../entities/event.dart';
|
import '../entities/event.dart';
|
||||||
import '../entities/loop_mode.dart';
|
import '../entities/loop_mode.dart';
|
||||||
import '../entities/playback_event.dart';
|
import '../entities/playback_event.dart';
|
||||||
import '../entities/queue_item.dart';
|
|
||||||
import '../entities/shuffle_mode.dart';
|
import '../entities/shuffle_mode.dart';
|
||||||
import '../entities/song.dart';
|
import '../entities/song.dart';
|
||||||
|
|
||||||
|
@ -12,8 +11,7 @@ abstract class AudioPlayerInfoRepository {
|
||||||
|
|
||||||
ValueStream<ShuffleMode> get shuffleModeStream;
|
ValueStream<ShuffleMode> get shuffleModeStream;
|
||||||
ValueStream<LoopMode> get loopModeStream;
|
ValueStream<LoopMode> get loopModeStream;
|
||||||
ValueStream<List<Song>> get songListStream;
|
ValueStream<List<Song>> get queueStream;
|
||||||
ValueStream<List<QueueItem>> get queueStream;
|
|
||||||
|
|
||||||
ValueStream<int> get currentIndexStream;
|
ValueStream<int> get currentIndexStream;
|
||||||
Stream<Song> get currentSongStream;
|
Stream<Song> get currentSongStream;
|
||||||
|
@ -28,14 +26,16 @@ abstract class AudioPlayerRepository extends AudioPlayerInfoRepository {
|
||||||
Future<void> stop();
|
Future<void> stop();
|
||||||
Future<bool> seekToNext();
|
Future<bool> seekToNext();
|
||||||
Future<void> seekToPrevious();
|
Future<void> seekToPrevious();
|
||||||
|
Future<void> seekToIndex(int index);
|
||||||
Future<void> dispose();
|
Future<void> dispose();
|
||||||
|
|
||||||
Future<void> playSong(Song song);
|
Future<void> playSong(Song song);
|
||||||
Future<void> loadQueue({List<QueueItem> queue, int initialIndex});
|
Future<void> loadQueue({List<Song> queue, int initialIndex});
|
||||||
Future<void> addToQueue(Song song);
|
Future<void> addToQueue(Song song);
|
||||||
|
Future<void> playNext(Song song);
|
||||||
Future<void> moveQueueItem(int oldIndex, int newIndex);
|
Future<void> moveQueueItem(int oldIndex, int newIndex);
|
||||||
Future<void> removeQueueIndex(int index);
|
Future<void> removeQueueIndex(int index);
|
||||||
Future<void> setIndex(int index);
|
Future<void> replaceQueueAroundIndex({List<Song> before, List<Song> after, int index});
|
||||||
|
|
||||||
/// Set the ShuffleMode. Does not affect playback/queue.
|
/// Set the ShuffleMode. Does not affect playback/queue.
|
||||||
Future<void> setShuffleMode(ShuffleMode shuffleMode);
|
Future<void> setShuffleMode(ShuffleMode shuffleMode);
|
||||||
|
|
30
lib/domain/usecases/add_to_queue.dart
Normal file
30
lib/domain/usecases/add_to_queue.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import '../entities/song.dart';
|
||||||
|
import '../modules/queue_manager.dart';
|
||||||
|
import '../repositories/audio_player_repository.dart';
|
||||||
|
import '../repositories/persistent_player_state_repository.dart';
|
||||||
|
import '../repositories/platform_integration_repository.dart';
|
||||||
|
|
||||||
|
class AddToQueue {
|
||||||
|
AddToQueue(
|
||||||
|
this._audioPlayerRepository,
|
||||||
|
this._platformIntegrationRepository,
|
||||||
|
this._playerStateRepository,
|
||||||
|
this._queueManagerModule,
|
||||||
|
);
|
||||||
|
|
||||||
|
final AudioPlayerRepository _audioPlayerRepository;
|
||||||
|
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||||
|
final PlayerStateRepository _playerStateRepository;
|
||||||
|
|
||||||
|
final QueueManagerModule _queueManagerModule;
|
||||||
|
|
||||||
|
Future<void> call(Song song) async {
|
||||||
|
|
||||||
|
_queueManagerModule.addToQueue(song);
|
||||||
|
await _audioPlayerRepository.addToQueue(song);
|
||||||
|
|
||||||
|
final songList = _audioPlayerRepository.queueStream.value;
|
||||||
|
print(songList.length);
|
||||||
|
_platformIntegrationRepository.setQueue(songList);
|
||||||
|
}
|
||||||
|
}
|
28
lib/domain/usecases/move_queue_item.dart
Normal file
28
lib/domain/usecases/move_queue_item.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import '../modules/queue_manager.dart';
|
||||||
|
import '../repositories/audio_player_repository.dart';
|
||||||
|
import '../repositories/persistent_player_state_repository.dart';
|
||||||
|
import '../repositories/platform_integration_repository.dart';
|
||||||
|
|
||||||
|
class MoveQueueItem {
|
||||||
|
MoveQueueItem(
|
||||||
|
this._audioPlayerRepository,
|
||||||
|
this._platformIntegrationRepository,
|
||||||
|
this._playerStateRepository,
|
||||||
|
this._queueManagerModule,
|
||||||
|
);
|
||||||
|
|
||||||
|
final AudioPlayerRepository _audioPlayerRepository;
|
||||||
|
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||||
|
final PlayerStateRepository _playerStateRepository;
|
||||||
|
|
||||||
|
final QueueManagerModule _queueManagerModule;
|
||||||
|
|
||||||
|
Future<void> call(int oldIndex, int newIndex) async {
|
||||||
|
|
||||||
|
_queueManagerModule.moveQueueItem(oldIndex, newIndex);
|
||||||
|
await _audioPlayerRepository.moveQueueItem(oldIndex, newIndex);
|
||||||
|
|
||||||
|
final songList = _audioPlayerRepository.queueStream.value;
|
||||||
|
_platformIntegrationRepository.setQueue(songList);
|
||||||
|
}
|
||||||
|
}
|
31
lib/domain/usecases/play_next.dart
Normal file
31
lib/domain/usecases/play_next.dart
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import '../entities/song.dart';
|
||||||
|
import '../modules/queue_manager.dart';
|
||||||
|
import '../repositories/audio_player_repository.dart';
|
||||||
|
import '../repositories/persistent_player_state_repository.dart';
|
||||||
|
import '../repositories/platform_integration_repository.dart';
|
||||||
|
|
||||||
|
class PlayNext {
|
||||||
|
PlayNext(
|
||||||
|
this._audioPlayerRepository,
|
||||||
|
this._platformIntegrationRepository,
|
||||||
|
this._playerStateRepository,
|
||||||
|
this._queueManagerModule,
|
||||||
|
);
|
||||||
|
|
||||||
|
final AudioPlayerRepository _audioPlayerRepository;
|
||||||
|
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||||
|
final PlayerStateRepository _playerStateRepository;
|
||||||
|
|
||||||
|
final QueueManagerModule _queueManagerModule;
|
||||||
|
|
||||||
|
Future<void> call(Song song) async {
|
||||||
|
final currentIndex = _audioPlayerRepository.currentIndexStream.value;
|
||||||
|
|
||||||
|
_queueManagerModule.insertIntoQueue(song, currentIndex + 1);
|
||||||
|
await _audioPlayerRepository.playNext(song);
|
||||||
|
|
||||||
|
final songList = _audioPlayerRepository.queueStream.value;
|
||||||
|
print(songList.length);
|
||||||
|
_platformIntegrationRepository.setQueue(songList);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
|
import '../entities/shuffle_mode.dart';
|
||||||
import '../entities/song.dart';
|
import '../entities/song.dart';
|
||||||
import '../modules/queue_generator.dart';
|
import '../modules/queue_manager.dart';
|
||||||
import '../repositories/audio_player_repository.dart';
|
import '../repositories/audio_player_repository.dart';
|
||||||
import '../repositories/persistent_player_state_repository.dart';
|
import '../repositories/persistent_player_state_repository.dart';
|
||||||
import '../repositories/platform_integration_repository.dart';
|
import '../repositories/platform_integration_repository.dart';
|
||||||
|
@ -16,27 +17,32 @@ class PlaySongs {
|
||||||
final PlatformIntegrationRepository _platformIntegrationRepository;
|
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||||
final PlayerStateRepository _playerStateRepository;
|
final PlayerStateRepository _playerStateRepository;
|
||||||
|
|
||||||
final QueueGenerationModule _queueGenerationModule;
|
final QueueManagerModule _queueGenerationModule;
|
||||||
|
|
||||||
Future<void> call({List<Song> songs, int initialIndex}) async {
|
Future<void> call({List<Song> songs, int initialIndex}) async {
|
||||||
if (0 <= initialIndex && initialIndex < songs.length) {
|
if (0 <= initialIndex && initialIndex < songs.length) {
|
||||||
// _audioPlayerRepository.playSong(songs[initialIndex]);
|
// _audioPlayerRepository.playSong(songs[initialIndex]);
|
||||||
|
|
||||||
final queueItems = await _queueGenerationModule.generateQueue(
|
final shuffleMode = _audioPlayerRepository.shuffleModeStream.value;
|
||||||
_audioPlayerRepository.shuffleModeStream.value,
|
|
||||||
|
await _queueGenerationModule.setQueue(
|
||||||
|
shuffleMode,
|
||||||
songs,
|
songs,
|
||||||
initialIndex,
|
initialIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final queueItems = _queueGenerationModule.queue;
|
||||||
|
final songList = queueItems.map((e) => e.song).toList();
|
||||||
|
|
||||||
await _audioPlayerRepository.loadQueue(
|
await _audioPlayerRepository.loadQueue(
|
||||||
initialIndex: initialIndex,
|
initialIndex: shuffleMode == ShuffleMode.none ? initialIndex : 0,
|
||||||
queue: queueItems,
|
queue: songList,
|
||||||
);
|
);
|
||||||
_audioPlayerRepository.play();
|
_audioPlayerRepository.play();
|
||||||
|
|
||||||
_platformIntegrationRepository.setCurrentSong(songs[initialIndex]);
|
_platformIntegrationRepository.setCurrentSong(songs[initialIndex]);
|
||||||
// _platformIntegrationRepository.play();
|
// _platformIntegrationRepository.play();
|
||||||
_platformIntegrationRepository.setQueue(queueItems.map((e) => e.song).toList());
|
_platformIntegrationRepository.setQueue(songList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
29
lib/domain/usecases/remove_queue_index.dart
Normal file
29
lib/domain/usecases/remove_queue_index.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import '../modules/queue_manager.dart';
|
||||||
|
import '../repositories/audio_player_repository.dart';
|
||||||
|
import '../repositories/persistent_player_state_repository.dart';
|
||||||
|
import '../repositories/platform_integration_repository.dart';
|
||||||
|
|
||||||
|
class RemoveQueueIndex {
|
||||||
|
RemoveQueueIndex(
|
||||||
|
this._audioPlayerRepository,
|
||||||
|
this._platformIntegrationRepository,
|
||||||
|
this._playerStateRepository,
|
||||||
|
this._queueManagerModule,
|
||||||
|
);
|
||||||
|
|
||||||
|
final AudioPlayerRepository _audioPlayerRepository;
|
||||||
|
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||||
|
final PlayerStateRepository _playerStateRepository;
|
||||||
|
|
||||||
|
final QueueManagerModule _queueManagerModule;
|
||||||
|
|
||||||
|
Future<void> call(int index) async {
|
||||||
|
|
||||||
|
_queueManagerModule.removeQueueIndex(index);
|
||||||
|
await _audioPlayerRepository.removeQueueIndex(index);
|
||||||
|
|
||||||
|
final songList = _audioPlayerRepository.queueStream.value;
|
||||||
|
print(songList.length);
|
||||||
|
_platformIntegrationRepository.setQueue(songList);
|
||||||
|
}
|
||||||
|
}
|
11
lib/domain/usecases/seek_to_index.dart
Normal file
11
lib/domain/usecases/seek_to_index.dart
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import '../repositories/audio_player_repository.dart';
|
||||||
|
|
||||||
|
class SeekToIndex {
|
||||||
|
SeekToIndex(this._audioPlayerRepository);
|
||||||
|
|
||||||
|
final AudioPlayerRepository _audioPlayerRepository;
|
||||||
|
|
||||||
|
Future<void> call(int index) async {
|
||||||
|
await _audioPlayerRepository.seekToIndex(index);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,5 @@
|
||||||
import 'package:mucke/domain/entities/queue_item.dart';
|
|
||||||
|
|
||||||
import '../entities/shuffle_mode.dart';
|
import '../entities/shuffle_mode.dart';
|
||||||
import '../entities/song.dart';
|
import '../modules/queue_manager.dart';
|
||||||
import '../modules/queue_generator.dart';
|
|
||||||
import '../repositories/audio_player_repository.dart';
|
import '../repositories/audio_player_repository.dart';
|
||||||
import '../repositories/persistent_player_state_repository.dart';
|
import '../repositories/persistent_player_state_repository.dart';
|
||||||
import '../repositories/platform_integration_repository.dart';
|
import '../repositories/platform_integration_repository.dart';
|
||||||
|
@ -12,53 +9,32 @@ class SetShuffleMode {
|
||||||
this._audioPlayerRepository,
|
this._audioPlayerRepository,
|
||||||
this._platformIntegrationRepository,
|
this._platformIntegrationRepository,
|
||||||
this._playerStateRepository,
|
this._playerStateRepository,
|
||||||
this._queueGenerationModule,
|
this._queueManagerModule,
|
||||||
);
|
);
|
||||||
|
|
||||||
final AudioPlayerRepository _audioPlayerRepository;
|
final AudioPlayerRepository _audioPlayerRepository;
|
||||||
final PlatformIntegrationRepository _platformIntegrationRepository;
|
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||||
final PlayerStateRepository _playerStateRepository;
|
final PlayerStateRepository _playerStateRepository;
|
||||||
|
|
||||||
final QueueGenerationModule _queueGenerationModule;
|
final QueueManagerModule _queueManagerModule;
|
||||||
|
|
||||||
Future<void> call(ShuffleMode shuffleMode) async {
|
Future<void> call(ShuffleMode shuffleMode) async {
|
||||||
// _audioPlayerRepository.playSong(songs[initialIndex]);
|
|
||||||
|
|
||||||
_audioPlayerRepository.setShuffleMode(shuffleMode);
|
_audioPlayerRepository.setShuffleMode(shuffleMode);
|
||||||
|
|
||||||
final queue = _audioPlayerRepository.queueStream.value;
|
|
||||||
final currentIndex = _audioPlayerRepository.currentIndexStream.value;
|
final currentIndex = _audioPlayerRepository.currentIndexStream.value;
|
||||||
|
final originalIndex = _queueManagerModule.queue[currentIndex].originalIndex;
|
||||||
|
|
||||||
final QueueItem currentQueueItem = queue[currentIndex];
|
await _queueManagerModule.reshuffleQueue(shuffleMode, currentIndex);
|
||||||
final int index = currentQueueItem.originalIndex;
|
final queue = _queueManagerModule.queue;
|
||||||
|
|
||||||
// WAS LETZTE GEDANKE?
|
final songList = queue.map((e) => e.song).toList();
|
||||||
// _inputQueue ist die originale Song Liste aus playSongs o.ä. BEVOR der QueueGenerator drüber läuft
|
final splitIndex = shuffleMode == ShuffleMode.none ? originalIndex : 0;
|
||||||
|
_audioPlayerRepository.replaceQueueAroundIndex(
|
||||||
|
index: currentIndex,
|
||||||
|
before: songList.sublist(0, splitIndex),
|
||||||
|
after: songList.sublist(splitIndex + 1),
|
||||||
|
);
|
||||||
|
|
||||||
// _queue = await _queueGenerator.generateQueue(shuffleMode, _inputQueue, index);
|
_platformIntegrationRepository.setQueue(songList);
|
||||||
// // TODO: maybe refactor _queue to a subject and listen for changes
|
|
||||||
// final songModelQueue = _queue.map((e) => e.song).toList();
|
|
||||||
// _queueSubject.add(_queue);
|
|
||||||
|
|
||||||
// final newQueue = _songModelsToAudioSource(songModelQueue);
|
|
||||||
// _updateQueue(newQueue, currentQueueItem);
|
|
||||||
|
|
||||||
// final queueItems = await _queueGenerationModule.generateQueue(
|
|
||||||
// shuffleMode,
|
|
||||||
// songs,
|
|
||||||
// initialIndex,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// final songList = queueItems.map((e) => e.song).toList();
|
|
||||||
|
|
||||||
// await _audioPlayerRepository.loadQueue(
|
|
||||||
// initialIndex: initialIndex,
|
|
||||||
// queue: songList,
|
|
||||||
// );
|
|
||||||
// _audioPlayerRepository.play();
|
|
||||||
|
|
||||||
// _platformIntegrationRepository.setCurrentSong(songs[initialIndex]);
|
|
||||||
// // _platformIntegrationRepository.play();
|
|
||||||
// _platformIntegrationRepository.setQueue(songList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:math';
|
||||||
|
|
||||||
import '../entities/shuffle_mode.dart';
|
import '../entities/shuffle_mode.dart';
|
||||||
import '../entities/song.dart';
|
import '../entities/song.dart';
|
||||||
import '../modules/queue_generator.dart';
|
import '../modules/queue_manager.dart';
|
||||||
import '../repositories/audio_player_repository.dart';
|
import '../repositories/audio_player_repository.dart';
|
||||||
import '../repositories/music_data_repository.dart';
|
import '../repositories/music_data_repository.dart';
|
||||||
import '../repositories/persistent_player_state_repository.dart';
|
import '../repositories/persistent_player_state_repository.dart';
|
||||||
|
@ -24,7 +24,7 @@ class ShuffleAll {
|
||||||
final PlatformIntegrationRepository _platformIntegrationRepository;
|
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||||
final PlayerStateRepository _playerStateRepository;
|
final PlayerStateRepository _playerStateRepository;
|
||||||
|
|
||||||
final QueueGenerationModule _queueGenerationModule;
|
final QueueManagerModule _queueGenerationModule;
|
||||||
|
|
||||||
Future<void> call() async {
|
Future<void> call() async {
|
||||||
final List<Song> songs = await _musicDataRepository.songStream.first;
|
final List<Song> songs = await _musicDataRepository.songStream.first;
|
||||||
|
@ -33,20 +33,23 @@ class ShuffleAll {
|
||||||
|
|
||||||
_audioPlayerRepository.setShuffleMode(SHUFFLE_MODE);
|
_audioPlayerRepository.setShuffleMode(SHUFFLE_MODE);
|
||||||
|
|
||||||
final queueItems = await _queueGenerationModule.generateQueue(
|
await _queueGenerationModule.setQueue(
|
||||||
SHUFFLE_MODE,
|
SHUFFLE_MODE,
|
||||||
songs,
|
songs,
|
||||||
index,
|
index,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final queueItems = _queueGenerationModule.queue;
|
||||||
|
final songList = queueItems.map((e) => e.song).toList();
|
||||||
|
|
||||||
await _audioPlayerRepository.loadQueue(
|
await _audioPlayerRepository.loadQueue(
|
||||||
initialIndex: 0,
|
initialIndex: 0,
|
||||||
queue: queueItems,
|
queue: songList,
|
||||||
);
|
);
|
||||||
_audioPlayerRepository.play();
|
_audioPlayerRepository.play();
|
||||||
|
|
||||||
_platformIntegrationRepository.setCurrentSong(songs[index]);
|
_platformIntegrationRepository.setCurrentSong(songs[index]);
|
||||||
// _platformIntegrationRepository.play();
|
// _platformIntegrationRepository.play();
|
||||||
_platformIntegrationRepository.setQueue(queueItems.map((e) => e.song).toList());
|
_platformIntegrationRepository.setQueue(songList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,27 @@ import 'package:just_audio/just_audio.dart';
|
||||||
|
|
||||||
import 'domain/actors/audio_player_actor.dart';
|
import 'domain/actors/audio_player_actor.dart';
|
||||||
import 'domain/actors/platform_integration_actor.dart';
|
import 'domain/actors/platform_integration_actor.dart';
|
||||||
import 'domain/modules/queue_generator.dart';
|
import 'domain/modules/queue_manager.dart';
|
||||||
import 'domain/repositories/audio_player_repository.dart';
|
import 'domain/repositories/audio_player_repository.dart';
|
||||||
import 'domain/repositories/music_data_modifier_repository.dart';
|
import 'domain/repositories/music_data_modifier_repository.dart';
|
||||||
import 'domain/repositories/music_data_repository.dart';
|
import 'domain/repositories/music_data_repository.dart';
|
||||||
import 'domain/repositories/persistent_player_state_repository.dart';
|
import 'domain/repositories/persistent_player_state_repository.dart';
|
||||||
import 'domain/repositories/platform_integration_repository.dart';
|
import 'domain/repositories/platform_integration_repository.dart';
|
||||||
import 'domain/repositories/settings_repository.dart';
|
import 'domain/repositories/settings_repository.dart';
|
||||||
|
import 'domain/usecases/add_to_queue.dart';
|
||||||
import 'domain/usecases/handle_playback_state.dart';
|
import 'domain/usecases/handle_playback_state.dart';
|
||||||
|
import 'domain/usecases/move_queue_item.dart';
|
||||||
import 'domain/usecases/pause.dart';
|
import 'domain/usecases/pause.dart';
|
||||||
import 'domain/usecases/play.dart';
|
import 'domain/usecases/play.dart';
|
||||||
|
import 'domain/usecases/play_next.dart';
|
||||||
import 'domain/usecases/play_songs.dart';
|
import 'domain/usecases/play_songs.dart';
|
||||||
|
import 'domain/usecases/remove_queue_index.dart';
|
||||||
|
import 'domain/usecases/seek_to_index.dart';
|
||||||
import 'domain/usecases/seek_to_next.dart';
|
import 'domain/usecases/seek_to_next.dart';
|
||||||
import 'domain/usecases/seek_to_previous.dart';
|
import 'domain/usecases/seek_to_previous.dart';
|
||||||
import 'domain/usecases/set_current_song.dart';
|
import 'domain/usecases/set_current_song.dart';
|
||||||
import 'domain/usecases/set_loop_mode.dart';
|
import 'domain/usecases/set_loop_mode.dart';
|
||||||
|
import 'domain/usecases/set_shuffle_mode.dart';
|
||||||
import 'domain/usecases/shuffle_all.dart';
|
import 'domain/usecases/shuffle_all.dart';
|
||||||
import 'domain/usecases/update_database.dart';
|
import 'domain/usecases/update_database.dart';
|
||||||
import 'presentation/state/audio_store.dart';
|
import 'presentation/state/audio_store.dart';
|
||||||
|
@ -64,12 +70,18 @@ Future<void> setupGetIt() async {
|
||||||
() {
|
() {
|
||||||
final audioStore = AudioStore(
|
final audioStore = AudioStore(
|
||||||
audioPlayerInfoRepository: getIt(),
|
audioPlayerInfoRepository: getIt(),
|
||||||
|
addToQueue: getIt(),
|
||||||
|
moveQueueItem: getIt(),
|
||||||
pause: getIt(),
|
pause: getIt(),
|
||||||
play: getIt(),
|
play: getIt(),
|
||||||
|
playNext: getIt(),
|
||||||
playSongs: getIt(),
|
playSongs: getIt(),
|
||||||
|
removeQueueIndex: getIt(),
|
||||||
|
seekToIndex: getIt(),
|
||||||
seekToNext: getIt(),
|
seekToNext: getIt(),
|
||||||
seekToPrevious: getIt(),
|
seekToPrevious: getIt(),
|
||||||
setLoopMode: getIt(),
|
setLoopMode: getIt(),
|
||||||
|
setShuffleMode: getIt(),
|
||||||
shuffleAll: getIt(),
|
shuffleAll: getIt(),
|
||||||
);
|
);
|
||||||
return audioStore;
|
return audioStore;
|
||||||
|
@ -83,11 +95,27 @@ Future<void> setupGetIt() async {
|
||||||
);
|
);
|
||||||
|
|
||||||
// use cases
|
// use cases
|
||||||
|
getIt.registerLazySingleton<AddToQueue>(
|
||||||
|
() => AddToQueue(
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
),
|
||||||
|
);
|
||||||
getIt.registerLazySingleton<HandlePlaybackEvent>(
|
getIt.registerLazySingleton<HandlePlaybackEvent>(
|
||||||
() => HandlePlaybackEvent(
|
() => HandlePlaybackEvent(
|
||||||
getIt(),
|
getIt(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
getIt.registerLazySingleton<MoveQueueItem>(
|
||||||
|
() => MoveQueueItem(
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
),
|
||||||
|
);
|
||||||
getIt.registerLazySingleton<Pause>(
|
getIt.registerLazySingleton<Pause>(
|
||||||
() => Pause(
|
() => Pause(
|
||||||
getIt(),
|
getIt(),
|
||||||
|
@ -98,6 +126,14 @@ Future<void> setupGetIt() async {
|
||||||
getIt(),
|
getIt(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
getIt.registerLazySingleton<PlayNext>(
|
||||||
|
() => PlayNext(
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
),
|
||||||
|
);
|
||||||
getIt.registerLazySingleton<PlaySongs>(
|
getIt.registerLazySingleton<PlaySongs>(
|
||||||
() => PlaySongs(
|
() => PlaySongs(
|
||||||
getIt(),
|
getIt(),
|
||||||
|
@ -106,6 +142,19 @@ Future<void> setupGetIt() async {
|
||||||
getIt(),
|
getIt(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
getIt.registerLazySingleton<RemoveQueueIndex>(
|
||||||
|
() => RemoveQueueIndex(
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
getIt.registerLazySingleton<SeekToIndex>(
|
||||||
|
() => SeekToIndex(
|
||||||
|
getIt(),
|
||||||
|
),
|
||||||
|
);
|
||||||
getIt.registerLazySingleton<SeekToNext>(
|
getIt.registerLazySingleton<SeekToNext>(
|
||||||
() => SeekToNext(
|
() => SeekToNext(
|
||||||
getIt(),
|
getIt(),
|
||||||
|
@ -126,6 +175,14 @@ Future<void> setupGetIt() async {
|
||||||
getIt(),
|
getIt(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
getIt.registerLazySingleton<SetShuffleMode>(
|
||||||
|
() => SetShuffleMode(
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
getIt(),
|
||||||
|
),
|
||||||
|
);
|
||||||
getIt.registerLazySingleton<ShuffleAll>(
|
getIt.registerLazySingleton<ShuffleAll>(
|
||||||
() => ShuffleAll(
|
() => ShuffleAll(
|
||||||
getIt(),
|
getIt(),
|
||||||
|
@ -142,8 +199,8 @@ Future<void> setupGetIt() async {
|
||||||
);
|
);
|
||||||
|
|
||||||
// modules
|
// modules
|
||||||
getIt.registerLazySingleton<QueueGenerationModule>(
|
getIt.registerLazySingleton<QueueManagerModule>(
|
||||||
() => QueueGenerationModule(
|
() => QueueManagerModule(
|
||||||
getIt(),
|
getIt(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -108,6 +108,13 @@ class AlbumDetailsPage extends StatelessWidget {
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Play next'),
|
||||||
|
onTap: () {
|
||||||
|
audioStore.playNext(song);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Add to queue'),
|
title: const Text('Add to queue'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|
|
@ -47,7 +47,7 @@ class QueuePage extends StatelessWidget {
|
||||||
subtitle: '${song.artist}',
|
subtitle: '${song.artist}',
|
||||||
albumArtPath: song.albumArtPath,
|
albumArtPath: song.albumArtPath,
|
||||||
highlight: index == activeIndex,
|
highlight: index == activeIndex,
|
||||||
onTap: () => audioStore.setIndex(index),
|
onTap: () => audioStore.seekToIndex(index),
|
||||||
),
|
),
|
||||||
onDismissed: (direction) {
|
onDismissed: (direction) {
|
||||||
audioStore.removeQueueIndex(index);
|
audioStore.removeQueueIndex(index);
|
||||||
|
|
|
@ -77,6 +77,13 @@ class _SongsPageState extends State<SongsPage>
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Play next'),
|
||||||
|
onTap: () {
|
||||||
|
audioStore.playNext(song);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Add to queue'),
|
title: const Text('Add to queue'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|
|
@ -7,45 +7,77 @@ import '../../domain/entities/loop_mode.dart';
|
||||||
import '../../domain/entities/shuffle_mode.dart';
|
import '../../domain/entities/shuffle_mode.dart';
|
||||||
import '../../domain/entities/song.dart';
|
import '../../domain/entities/song.dart';
|
||||||
import '../../domain/repositories/audio_player_repository.dart';
|
import '../../domain/repositories/audio_player_repository.dart';
|
||||||
|
import '../../domain/usecases/add_to_queue.dart';
|
||||||
|
import '../../domain/usecases/move_queue_item.dart';
|
||||||
import '../../domain/usecases/pause.dart';
|
import '../../domain/usecases/pause.dart';
|
||||||
import '../../domain/usecases/play.dart';
|
import '../../domain/usecases/play.dart';
|
||||||
|
import '../../domain/usecases/play_next.dart';
|
||||||
import '../../domain/usecases/play_songs.dart';
|
import '../../domain/usecases/play_songs.dart';
|
||||||
|
import '../../domain/usecases/remove_queue_index.dart';
|
||||||
|
import '../../domain/usecases/seek_to_index.dart';
|
||||||
import '../../domain/usecases/seek_to_next.dart';
|
import '../../domain/usecases/seek_to_next.dart';
|
||||||
import '../../domain/usecases/seek_to_previous.dart';
|
import '../../domain/usecases/seek_to_previous.dart';
|
||||||
import '../../domain/usecases/set_loop_mode.dart';
|
import '../../domain/usecases/set_loop_mode.dart';
|
||||||
|
import '../../domain/usecases/set_shuffle_mode.dart';
|
||||||
import '../../domain/usecases/shuffle_all.dart';
|
import '../../domain/usecases/shuffle_all.dart';
|
||||||
|
|
||||||
part 'audio_store.g.dart';
|
part 'audio_store.g.dart';
|
||||||
|
|
||||||
class AudioStore extends _AudioStore with _$AudioStore {
|
class AudioStore extends _AudioStore with _$AudioStore {
|
||||||
AudioStore({
|
AudioStore({
|
||||||
|
@required AddToQueue addToQueue,
|
||||||
|
@required MoveQueueItem moveQueueItem,
|
||||||
@required Pause pause,
|
@required Pause pause,
|
||||||
@required Play play,
|
@required Play play,
|
||||||
|
@required PlayNext playNext,
|
||||||
@required PlaySongs playSongs,
|
@required PlaySongs playSongs,
|
||||||
|
@required RemoveQueueIndex removeQueueIndex,
|
||||||
|
@required SeekToIndex seekToIndex,
|
||||||
@required SeekToNext seekToNext,
|
@required SeekToNext seekToNext,
|
||||||
@required SeekToPrevious seekToPrevious,
|
@required SeekToPrevious seekToPrevious,
|
||||||
@required SetLoopMode setLoopMode,
|
@required SetLoopMode setLoopMode,
|
||||||
|
@required SetShuffleMode setShuffleMode,
|
||||||
@required ShuffleAll shuffleAll,
|
@required ShuffleAll shuffleAll,
|
||||||
@required AudioPlayerInfoRepository audioPlayerInfoRepository,
|
@required AudioPlayerInfoRepository audioPlayerInfoRepository,
|
||||||
}) : super(playSongs, audioPlayerInfoRepository, pause, play, seekToNext, seekToPrevious,
|
}) : super(
|
||||||
setLoopMode, shuffleAll);
|
addToQueue,
|
||||||
|
moveQueueItem,
|
||||||
|
playSongs,
|
||||||
|
audioPlayerInfoRepository,
|
||||||
|
pause,
|
||||||
|
play,
|
||||||
|
playNext,
|
||||||
|
removeQueueIndex,
|
||||||
|
seekToIndex,
|
||||||
|
seekToNext,
|
||||||
|
seekToPrevious,
|
||||||
|
setLoopMode,
|
||||||
|
setShuffleMode,
|
||||||
|
shuffleAll,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _AudioStore with Store {
|
abstract class _AudioStore with Store {
|
||||||
_AudioStore(
|
_AudioStore(
|
||||||
|
this._addToQueue,
|
||||||
|
this._moveQueueItem,
|
||||||
this._playSongs,
|
this._playSongs,
|
||||||
this._audioPlayerInfoRepository,
|
this._audioPlayerInfoRepository,
|
||||||
this._pause,
|
this._pause,
|
||||||
this._play,
|
this._play,
|
||||||
|
this._playNext,
|
||||||
|
this._removeQueueIndex,
|
||||||
|
this._seekToIndex,
|
||||||
this._seekToNext,
|
this._seekToNext,
|
||||||
this._seekToPrevious,
|
this._seekToPrevious,
|
||||||
this._setLoopMode,
|
this._setLoopMode,
|
||||||
|
this._setShuffleMode,
|
||||||
this._shuffleAll,
|
this._shuffleAll,
|
||||||
) {
|
) {
|
||||||
currentPositionStream = _audioPlayerInfoRepository.positionStream
|
currentPositionStream = _audioPlayerInfoRepository.positionStream
|
||||||
.asObservable(initialValue: const Duration(seconds: 0));
|
.asObservable(initialValue: const Duration(seconds: 0));
|
||||||
|
|
||||||
queueStream = _audioPlayerInfoRepository.songListStream.asObservable();
|
queueStream = _audioPlayerInfoRepository.queueStream.asObservable();
|
||||||
|
|
||||||
queueIndexStream = _audioPlayerInfoRepository.currentIndexStream.asObservable();
|
queueIndexStream = _audioPlayerInfoRepository.currentIndexStream.asObservable();
|
||||||
|
|
||||||
|
@ -60,12 +92,18 @@ abstract class _AudioStore with Store {
|
||||||
|
|
||||||
final AudioPlayerInfoRepository _audioPlayerInfoRepository;
|
final AudioPlayerInfoRepository _audioPlayerInfoRepository;
|
||||||
|
|
||||||
|
final AddToQueue _addToQueue;
|
||||||
|
final MoveQueueItem _moveQueueItem;
|
||||||
final Pause _pause;
|
final Pause _pause;
|
||||||
final Play _play;
|
final Play _play;
|
||||||
|
final PlayNext _playNext;
|
||||||
final PlaySongs _playSongs;
|
final PlaySongs _playSongs;
|
||||||
|
final RemoveQueueIndex _removeQueueIndex;
|
||||||
|
final SeekToIndex _seekToIndex;
|
||||||
final SeekToNext _seekToNext;
|
final SeekToNext _seekToNext;
|
||||||
final SeekToPrevious _seekToPrevious;
|
final SeekToPrevious _seekToPrevious;
|
||||||
final SetLoopMode _setLoopMode;
|
final SetLoopMode _setLoopMode;
|
||||||
|
final SetShuffleMode _setShuffleMode;
|
||||||
final ShuffleAll _shuffleAll;
|
final ShuffleAll _shuffleAll;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
|
@ -77,6 +115,8 @@ abstract class _AudioStore with Store {
|
||||||
@observable
|
@observable
|
||||||
ObservableStream<Duration> currentPositionStream;
|
ObservableStream<Duration> currentPositionStream;
|
||||||
|
|
||||||
|
// beware that this only triggers reactions when a new list (new reference) is set
|
||||||
|
// doesn't work if the same reference is added to BehaviorSubject
|
||||||
@observable
|
@observable
|
||||||
ObservableStream<List<Song>> queueStream;
|
ObservableStream<List<Song>> queueStream;
|
||||||
|
|
||||||
|
@ -109,12 +149,12 @@ abstract class _AudioStore with Store {
|
||||||
_seekToPrevious();
|
_seekToPrevious();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setIndex(int index) async {
|
Future<void> seekToIndex(int index) async {
|
||||||
// _audioInterface.setIndex(index);
|
_seekToIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setShuffleMode(ShuffleMode shuffleMode) async {
|
Future<void> setShuffleMode(ShuffleMode shuffleMode) async {
|
||||||
// _audioInterface.setShuffleMode(shuffleMode);
|
_setShuffleMode(shuffleMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setLoopMode(LoopMode loopMode) async {
|
Future<void> setLoopMode(LoopMode loopMode) async {
|
||||||
|
@ -126,15 +166,19 @@ abstract class _AudioStore with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addToQueue(Song song) async {
|
Future<void> addToQueue(Song song) async {
|
||||||
// _audioInterface.addToQueue(song);
|
_addToQueue(song);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> playNext(Song song) async {
|
||||||
|
_playNext(song);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> moveQueueItem(int oldIndex, int newIndex) async {
|
Future<void> moveQueueItem(int oldIndex, int newIndex) async {
|
||||||
// _audioInterface.moveQueueItem(oldIndex, newIndex);
|
_moveQueueItem(oldIndex, newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removeQueueIndex(int index) async {
|
Future<void> removeQueueIndex(int index) async {
|
||||||
// _audioInterface.removeQueueIndex(index);
|
_removeQueueIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> playAlbum(Album album) async {
|
Future<void> playAlbum(Album album) async {
|
||||||
|
|
|
@ -18,8 +18,6 @@ class AlbumArt extends StatelessWidget {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(2.0),
|
borderRadius: BorderRadius.circular(2.0),
|
||||||
boxShadow: const [
|
boxShadow: const [
|
||||||
BoxShadow(color: Colors.black45, blurRadius: 1, offset: Offset(0, 1)),
|
|
||||||
BoxShadow(color: Colors.black38, blurRadius: 5, offset: Offset(0, 1)),
|
|
||||||
BoxShadow(color: Colors.black26, blurRadius: 8, offset: Offset(0, 1)),
|
BoxShadow(color: Colors.black26, blurRadius: 8, offset: Offset(0, 1)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -33,22 +31,6 @@ class AlbumArt extends StatelessWidget {
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
height: 150,
|
|
||||||
child: Container(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: [Color(0x00000000), Color(0xBB000000)],
|
|
||||||
stops: [0.0, 1.0],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import '../models/song_model.dart';
|
||||||
|
|
||||||
abstract class AudioPlayerDataSource {
|
abstract class AudioPlayerDataSource {
|
||||||
ValueStream<int> get currentIndexStream;
|
ValueStream<int> get currentIndexStream;
|
||||||
ValueStream<SongModel> get currentSongStream;
|
// ValueStream<SongModel> get currentSongStream;
|
||||||
Stream<PlaybackEventModel> get playbackEventStream;
|
Stream<PlaybackEventModel> get playbackEventStream;
|
||||||
ValueStream<bool> get playingStream;
|
ValueStream<bool> get playingStream;
|
||||||
ValueStream<Duration> get positionStream;
|
ValueStream<Duration> get positionStream;
|
||||||
|
@ -21,10 +21,10 @@ abstract class AudioPlayerDataSource {
|
||||||
Future<void> loadQueue({List<SongModel> queue, int initialIndex});
|
Future<void> loadQueue({List<SongModel> queue, int initialIndex});
|
||||||
Future<void> addToQueue(SongModel song);
|
Future<void> addToQueue(SongModel song);
|
||||||
Future<void> moveQueueItem(int oldIndex, int newIndex);
|
Future<void> moveQueueItem(int oldIndex, int newIndex);
|
||||||
|
Future<void> playNext(SongModel song);
|
||||||
Future<void> removeQueueIndex(int index);
|
Future<void> removeQueueIndex(int index);
|
||||||
Future<void> setIndex(int index);
|
Future<void> replaceQueueAroundIndex({List<SongModel> before, List<SongModel> after, int index});
|
||||||
|
Future<void> seekToIndex(int index);
|
||||||
|
|
||||||
Future<void> setLoopMode(LoopMode loopMode);
|
Future<void> setLoopMode(LoopMode loopMode);
|
||||||
|
|
||||||
Future<void> playSongList(List<SongModel> songs, int startIndex);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:just_audio/just_audio.dart' as ja;
|
import 'package:just_audio/just_audio.dart' as ja;
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
@ -8,24 +10,25 @@ import '../models/playback_event_model.dart';
|
||||||
import '../models/song_model.dart';
|
import '../models/song_model.dart';
|
||||||
import 'audio_player_data_source.dart';
|
import 'audio_player_data_source.dart';
|
||||||
|
|
||||||
|
/// beide fälle (start > ende und ende <= start) beim initialen laden schon behandeln
|
||||||
|
/// offset berechnung passt -> damit sollte die index ausgabe auch stimmen
|
||||||
|
/// vielleicht lässt sich allgemeiner fall mit modulo rechnung finden: loadIndex = (li+-1) % length
|
||||||
|
/// die beiden richtungen (skip next/prev) verhalten sich in den beiden fällen genau gegensätzlich
|
||||||
|
|
||||||
|
const int LOAD_INTERVAL = 2;
|
||||||
|
|
||||||
class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
AudioPlayerDataSourceImpl(this._audioPlayer) {
|
AudioPlayerDataSourceImpl(this._audioPlayer) {
|
||||||
_audioPlayer.currentIndexStream.listen((event) {
|
_audioPlayer.currentIndexStream.listen((index) async {
|
||||||
_log.info('currentIndex: $event');
|
_log.info('currentIndexSteam.listen: $index');
|
||||||
_currentIndexSubject.add(event);
|
if (!await _updateLoadedQueue(index)) {
|
||||||
if (_queue != null && event != null && event < _queue.length) {
|
_updateCurrentIndex(index);
|
||||||
_currentSongSubject.add(_queue[event]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_audioPlayer.playingStream.listen((event) {
|
_audioPlayer.playingStream.listen((event) => _playingSubject.add(event));
|
||||||
_log.info('playing: $event');
|
|
||||||
_playingSubject.add(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
_audioPlayer.positionStream.listen((event) {
|
_audioPlayer.positionStream.listen((event) => _positionSubject.add(event));
|
||||||
_positionSubject.add(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
_playbackEventModelStream = Rx.combineLatest2<ja.PlaybackEvent, bool, PlaybackEventModel>(
|
_playbackEventModelStream = Rx.combineLatest2<ja.PlaybackEvent, bool, PlaybackEventModel>(
|
||||||
_audioPlayer.playbackEventStream,
|
_audioPlayer.playbackEventStream,
|
||||||
|
@ -40,29 +43,43 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
static final _log = Logger('AudioPlayer');
|
static final _log = Logger('AudioPlayer');
|
||||||
|
|
||||||
final BehaviorSubject<int> _currentIndexSubject = BehaviorSubject();
|
final BehaviorSubject<int> _currentIndexSubject = BehaviorSubject();
|
||||||
final BehaviorSubject<SongModel> _currentSongSubject = BehaviorSubject();
|
|
||||||
final BehaviorSubject<PlaybackEventModel> _playbackEventSubject = BehaviorSubject();
|
final BehaviorSubject<PlaybackEventModel> _playbackEventSubject = BehaviorSubject();
|
||||||
final BehaviorSubject<bool> _playingSubject = BehaviorSubject();
|
final BehaviorSubject<bool> _playingSubject = BehaviorSubject();
|
||||||
final BehaviorSubject<Duration> _positionSubject = BehaviorSubject();
|
final BehaviorSubject<Duration> _positionSubject = BehaviorSubject();
|
||||||
|
|
||||||
Stream<PlaybackEventModel> _playbackEventModelStream;
|
Stream<PlaybackEventModel> _playbackEventModelStream;
|
||||||
List<SongModel> _queue;
|
List<SongModel> _queue;
|
||||||
|
int _loadStartIndex;
|
||||||
|
int _loadEndIndex;
|
||||||
|
|
||||||
void _setQueue(List<SongModel> queue, {int index}) {
|
set loadStartIndex(int i) {
|
||||||
_queue = queue;
|
_loadStartIndex = i;
|
||||||
if (index != null) {
|
_log.info('loadStartIndex <- $i');
|
||||||
_currentSongSubject.add(_queue[index]);
|
// _updateCurrentIndex(_audioPlayer.currentIndex);
|
||||||
} else if (_currentIndexSubject.value != null) {
|
}
|
||||||
_currentSongSubject.add(_queue[_currentIndexSubject.value]);
|
|
||||||
|
int get loadStartIndex => _loadStartIndex;
|
||||||
|
|
||||||
|
set loadEndIndex(int i) {
|
||||||
|
_loadEndIndex = i;
|
||||||
|
_log.info('loadEndIndex <- $i');
|
||||||
|
// _updateCurrentIndex(_audioPlayer.currentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get loadEndIndex => _loadEndIndex;
|
||||||
|
|
||||||
|
int get loadOffset {
|
||||||
|
if (loadStartIndex != null && loadEndIndex != null) {
|
||||||
|
final offset = loadStartIndex < loadEndIndex ? loadStartIndex : loadStartIndex - loadEndIndex;
|
||||||
|
print('offset: $offset');
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValueStream<int> get currentIndexStream => _currentIndexSubject.stream;
|
ValueStream<int> get currentIndexStream => _currentIndexSubject.stream;
|
||||||
|
|
||||||
@override
|
|
||||||
ValueStream<SongModel> get currentSongStream => _currentSongSubject.stream;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<PlaybackEventModel> get playbackEventStream => _playbackEventModelStream;
|
Stream<PlaybackEventModel> get playbackEventStream => _playbackEventModelStream;
|
||||||
|
|
||||||
|
@ -75,7 +92,6 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
await _currentIndexSubject.close();
|
await _currentIndexSubject.close();
|
||||||
await _currentSongSubject.close();
|
|
||||||
await _playbackEventSubject.close();
|
await _playbackEventSubject.close();
|
||||||
await _positionSubject.close();
|
await _positionSubject.close();
|
||||||
await _audioPlayer.dispose();
|
await _audioPlayer.dispose();
|
||||||
|
@ -86,12 +102,18 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
if (queue == null || initialIndex == null || initialIndex >= queue.length) {
|
if (queue == null || initialIndex == null || initialIndex >= queue.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_setQueue(queue, index: initialIndex);
|
_queue = queue;
|
||||||
|
|
||||||
// final smallQueue = queue.sublist(max(initialIndex - 10, 0), min(initialIndex + 140, queue.length));
|
loadStartIndex = max(initialIndex - LOAD_INTERVAL, 0);
|
||||||
|
loadEndIndex = min(initialIndex + LOAD_INTERVAL + 1, queue.length);
|
||||||
|
|
||||||
_audioSource = _songModelsToAudioSource(queue);
|
final smallQueue = queue.sublist(loadStartIndex, loadEndIndex);
|
||||||
_audioPlayer.setAudioSource(_audioSource, initialIndex: initialIndex);
|
|
||||||
|
_audioSource = _songModelsToAudioSource(smallQueue);
|
||||||
|
|
||||||
|
// _loadStartIndex.add(loadStartIndex);
|
||||||
|
// _loadEndIndex.add(loadEndIndex);
|
||||||
|
_audioPlayer.setAudioSource(_audioSource, initialIndex: initialIndex - loadStartIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -104,26 +126,6 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
_audioPlayer.play();
|
_audioPlayer.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> playSongList(List<SongModel> songs, int startIndex) async {
|
|
||||||
// _inputQueue = songs;
|
|
||||||
|
|
||||||
// final firstSong = songs[startIndex];
|
|
||||||
// _queueSubject.add([QueueItemModel(firstSong, originalIndex: startIndex)]);
|
|
||||||
// _audioSource = _songModelsToAudioSource([firstSong]);
|
|
||||||
// await _audioPlayer.setAudioSource(_audioSource);
|
|
||||||
// _audioPlayer.play();
|
|
||||||
|
|
||||||
// _queue = await _queueGenerator.generateQueue(_shuffleModeSubject.value, songs, startIndex);
|
|
||||||
// final songModelQueue = _queue.map((e) => e.song).toList();
|
|
||||||
// _queueSubject.add(_queue);
|
|
||||||
|
|
||||||
// final int splitIndex = _shuffleModeSubject.value == ShuffleMode.none ? startIndex : 0;
|
|
||||||
// final newQueue = _songModelsToAudioSource(songModelQueue);
|
|
||||||
// await _audioSource.insertAll(0, newQueue.children.sublist(0, splitIndex));
|
|
||||||
// _audioSource.addAll(newQueue.children.sublist(splitIndex + 1, newQueue.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> seekToNext() async {
|
Future<bool> seekToNext() async {
|
||||||
final result = _audioPlayer.hasNext;
|
final result = _audioPlayer.hasNext;
|
||||||
|
@ -141,7 +143,7 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setIndex(int index) async {
|
Future<void> seekToIndex(int index) async {
|
||||||
await _audioPlayer.seek(const Duration(seconds: 0), index: index);
|
await _audioPlayer.seek(const Duration(seconds: 0), index: index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,43 +155,43 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
@override
|
@override
|
||||||
Future<void> addToQueue(SongModel song) async {
|
Future<void> addToQueue(SongModel song) async {
|
||||||
await _audioSource.add(ja.AudioSource.uri(Uri.file(song.path)));
|
await _audioSource.add(ja.AudioSource.uri(Uri.file(song.path)));
|
||||||
// _queue.add(QueueItemModel(song, originalIndex: -1, type: QueueItemType.added));
|
_queue.add(song);
|
||||||
// _queueSubject.add(_queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> moveQueueItem(int oldIndex, int newIndex) async {
|
Future<void> moveQueueItem(int oldIndex, int newIndex) async {
|
||||||
// final QueueItemModel queueItem = _queue.removeAt(oldIndex);
|
|
||||||
// _queue.insert(newIndex, queueItem);
|
|
||||||
// _queueSubject.add(_queue);
|
|
||||||
await _audioSource.move(oldIndex, newIndex);
|
await _audioSource.move(oldIndex, newIndex);
|
||||||
|
final song = _queue.removeAt(oldIndex);
|
||||||
|
_queue.insert(newIndex, song);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> playNext(SongModel song) async {
|
||||||
|
final index = currentIndexStream.value + 1;
|
||||||
|
await _audioSource.insert(index, ja.AudioSource.uri(Uri.file(song.path)));
|
||||||
|
_queue.insert(index, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> removeQueueIndex(int index) async {
|
Future<void> removeQueueIndex(int index) async {
|
||||||
// _queue.removeAt(index);
|
|
||||||
// _queueSubject.add(_queue);
|
|
||||||
await _audioSource.removeAt(index);
|
await _audioSource.removeAt(index);
|
||||||
|
_queue.removeAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @override
|
@override
|
||||||
// Future<void> setShuffleMode(ShuffleMode shuffleMode, bool updateQueue) async {
|
Future<void> replaceQueueAroundIndex(
|
||||||
// _log.info('setShuffleMode: $shuffleMode');
|
{List<SongModel> before, List<SongModel> after, int index}) async {
|
||||||
// if (shuffleMode == null) return;
|
_queue = before + [_queue[index]] + after;
|
||||||
// _shuffleModeSubject.add(shuffleMode);
|
|
||||||
|
|
||||||
// if (updateQueue) {
|
final _before = _songModelsToAudioSource(before);
|
||||||
// final QueueItem currentQueueItem = _queue[_currentIndexSubject.value];
|
final _after = _songModelsToAudioSource(after);
|
||||||
// final int index = currentQueueItem.originalIndex;
|
|
||||||
// _queue = await _queueGenerator.generateQueue(shuffleMode, _inputQueue, index);
|
|
||||||
// // TODO: maybe refactor _queue to a subject and listen for changes
|
|
||||||
// final songModelQueue = _queue.map((e) => e.song).toList();
|
|
||||||
// _queueSubject.add(_queue);
|
|
||||||
|
|
||||||
// final newQueue = _songModelsToAudioSource(songModelQueue);
|
await _audioSource.removeRange(0, index);
|
||||||
// _updateQueue(newQueue, currentQueueItem);
|
await _audioSource.removeRange(1, _audioSource.length);
|
||||||
// }
|
|
||||||
// }
|
await _audioSource.insertAll(0, _before.children);
|
||||||
|
await _audioSource.addAll(_after.children);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setLoopMode(LoopMode loopMode) async {
|
Future<void> setLoopMode(LoopMode loopMode) async {
|
||||||
|
@ -203,32 +205,117 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> _updateQueue(
|
/// extend the loaded audiosource, when seeking to previous/next
|
||||||
// ja.ConcatenatingAudioSource newQueue, QueueItem currentQueueItem) async {
|
Future<bool> _updateLoadedQueue(int newIndex) async {
|
||||||
// final int index = currentQueueItem.originalIndex;
|
_log.info('updateLoadedQueue: $newIndex');
|
||||||
|
_log.info('[$loadStartIndex, $loadEndIndex]');
|
||||||
|
|
||||||
// _audioSource.removeRange(0, _currentIndexSubject.value);
|
if (loadStartIndex == null || loadEndIndex == null || newIndex == null) return false;
|
||||||
// _audioSource.removeRange(1, _audioSource.length);
|
|
||||||
|
|
||||||
// if (_shuffleModeSubject.value == ShuffleMode.none) {
|
if (loadStartIndex == loadEndIndex || (loadStartIndex == 0 && loadEndIndex == _queue.length))
|
||||||
// switch (currentQueueItem.type) {
|
return false;
|
||||||
// case QueueItemType.added:
|
|
||||||
// case QueueItemType.standard:
|
if (loadStartIndex < loadEndIndex) {
|
||||||
// await _audioSource.insertAll(0, newQueue.children.sublist(0, index));
|
_log.info('base case');
|
||||||
// _audioSource.addAll(newQueue.children.sublist(index + 1));
|
return await _updateLoadedQueueBaseCase(newIndex);
|
||||||
// break;
|
} else {
|
||||||
// case QueueItemType.predecessor:
|
_log.info('inverted case');
|
||||||
// await _audioSource.insertAll(0, newQueue.children.sublist(0, index));
|
return await _updateLoadedQueueInverted(newIndex);
|
||||||
// _audioSource.addAll(newQueue.children.sublist(index));
|
}
|
||||||
// break;
|
}
|
||||||
// case QueueItemType.successor:
|
|
||||||
// await _audioSource.insertAll(0, newQueue.children.sublist(0, index + 1));
|
Future<bool> _updateLoadedQueueBaseCase(int newIndex) async {
|
||||||
// _audioSource.addAll(newQueue.children.sublist(index + 1));
|
if (newIndex < LOAD_INTERVAL) {
|
||||||
// break;
|
// nearing the start of the loaded songs
|
||||||
// }
|
if (loadStartIndex > 0) {
|
||||||
// _currentIndexSubject.add(index);
|
// load the song previous to the already loaded songs
|
||||||
// } else {
|
_log.info('loadStartIndex--');
|
||||||
// _audioSource.addAll(newQueue.children.sublist(1));
|
loadStartIndex--;
|
||||||
// }
|
await _audioSource.insert(0, ja.AudioSource.uri(Uri.file(_queue[loadStartIndex].path)));
|
||||||
// }
|
return true;
|
||||||
|
} else if (loadEndIndex < _queue.length) {
|
||||||
|
// load the last song, if it isn't already loaded
|
||||||
|
_log.info('loadStartIndex = ${_queue.length - 1}');
|
||||||
|
loadStartIndex = _queue.length - 1;
|
||||||
|
await _audioSource.add(ja.AudioSource.uri(Uri.file(_queue.last.path)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (newIndex > _audioSource.length - LOAD_INTERVAL - 1) {
|
||||||
|
// need to load next song
|
||||||
|
if (loadEndIndex < _queue.length) {
|
||||||
|
// we ARE NOT at the end of the queue -> load next song
|
||||||
|
_log.info('loadEndIndex++');
|
||||||
|
loadEndIndex++;
|
||||||
|
await _audioSource.add(ja.AudioSource.uri(Uri.file(_queue[loadEndIndex - 1].path)));
|
||||||
|
return false;
|
||||||
|
} else if (loadStartIndex > 0) {
|
||||||
|
// we ARE at the end of the queue AND the first song has not been loaded yet
|
||||||
|
// -> load first song
|
||||||
|
_log.info('loadEndIndex = 1');
|
||||||
|
loadEndIndex = 1;
|
||||||
|
await _audioSource.insert(0, ja.AudioSource.uri(Uri.file(_queue[0].path)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _updateLoadedQueueInverted(int newIndex) async {
|
||||||
|
final rightOfLoadEnd = newIndex >= loadEndIndex;
|
||||||
|
|
||||||
|
int leftBorder = newIndex - LOAD_INTERVAL;
|
||||||
|
if (newIndex < loadEndIndex) {
|
||||||
|
leftBorder += _audioSource.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rightBorder = newIndex + LOAD_INTERVAL;
|
||||||
|
if (newIndex > loadEndIndex) {
|
||||||
|
rightBorder -= _audioSource.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftBorder < loadEndIndex) {
|
||||||
|
// nearing the start of the loaded songs
|
||||||
|
// load the song previous to the already loaded songs
|
||||||
|
_log.info('inv: loadStartIndex--');
|
||||||
|
loadStartIndex--;
|
||||||
|
await _audioSource.insert(
|
||||||
|
loadEndIndex, ja.AudioSource.uri(Uri.file(_queue[loadStartIndex].path)));
|
||||||
|
return rightOfLoadEnd;
|
||||||
|
} else if (rightBorder >= loadEndIndex) {
|
||||||
|
// need to load next song
|
||||||
|
// we ARE NOT at the end of the queue -> load next song
|
||||||
|
_log.info('inv: loadEndIndex++');
|
||||||
|
loadEndIndex++;
|
||||||
|
await _audioSource.insert(
|
||||||
|
loadEndIndex - 1, ja.AudioSource.uri(Uri.file(_queue[loadEndIndex - 1].path)));
|
||||||
|
return rightOfLoadEnd;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateCurrentIndex(int apIndex) {
|
||||||
|
if (loadStartIndex == null || loadEndIndex == null) {
|
||||||
|
_currentIndexSubject.add(apIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result;
|
||||||
|
if (_audioSource != null && _audioSource.length == _queue.length) {
|
||||||
|
_log.info('EVERYTHING LOADED');
|
||||||
|
result = apIndex;
|
||||||
|
} else if (loadStartIndex < loadEndIndex) {
|
||||||
|
// base case
|
||||||
|
result = apIndex != null ? (apIndex + (loadStartIndex ?? 0)) : null;
|
||||||
|
} else {
|
||||||
|
// inverted case
|
||||||
|
if (apIndex < loadEndIndex) {
|
||||||
|
result = apIndex;
|
||||||
|
} else {
|
||||||
|
result = apIndex + (loadStartIndex - loadEndIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentIndexSubject.add(result);
|
||||||
|
_log.info('updateCurrentIndex: $result');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'package:rxdart/rxdart.dart';
|
||||||
|
|
||||||
import '../../domain/entities/loop_mode.dart';
|
import '../../domain/entities/loop_mode.dart';
|
||||||
import '../../domain/entities/playback_event.dart';
|
import '../../domain/entities/playback_event.dart';
|
||||||
import '../../domain/entities/queue_item.dart';
|
|
||||||
import '../../domain/entities/shuffle_mode.dart';
|
import '../../domain/entities/shuffle_mode.dart';
|
||||||
import '../../domain/entities/song.dart';
|
import '../../domain/entities/song.dart';
|
||||||
import '../../domain/repositories/audio_player_repository.dart';
|
import '../../domain/repositories/audio_player_repository.dart';
|
||||||
|
@ -13,15 +12,22 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
AudioPlayerRepositoryImpl(this._audioPlayerDataSource) {
|
AudioPlayerRepositoryImpl(this._audioPlayerDataSource) {
|
||||||
_shuffleModeSubject.add(ShuffleMode.none);
|
_shuffleModeSubject.add(ShuffleMode.none);
|
||||||
_loopModeSubject.add(LoopMode.off);
|
_loopModeSubject.add(LoopMode.off);
|
||||||
|
|
||||||
|
_audioPlayerDataSource.currentIndexStream.listen(
|
||||||
|
(index) {
|
||||||
|
print('CURRENT INDEX: $index');
|
||||||
|
_updateCurrentSong(queueStream.value, index);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_queueSubject.listen((queue) => _updateCurrentSong(queue, currentIndexStream.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
final AudioPlayerDataSource _audioPlayerDataSource;
|
final AudioPlayerDataSource _audioPlayerDataSource;
|
||||||
|
|
||||||
// final BehaviorSubject<int> _currentIndexSubject = BehaviorSubject();
|
// final BehaviorSubject<int> _currentIndexSubject = BehaviorSubject();
|
||||||
// final BehaviorSubject<Song> _currentSongSubject = BehaviorSubject<Song>();
|
final BehaviorSubject<Song> _currentSongSubject = BehaviorSubject<Song>();
|
||||||
final BehaviorSubject<LoopMode> _loopModeSubject = BehaviorSubject();
|
final BehaviorSubject<LoopMode> _loopModeSubject = BehaviorSubject();
|
||||||
final BehaviorSubject<List<Song>> _songListSubject = BehaviorSubject();
|
final BehaviorSubject<List<Song>> _queueSubject = BehaviorSubject();
|
||||||
final BehaviorSubject<List<QueueItem>> _queueSubject = BehaviorSubject();
|
|
||||||
final BehaviorSubject<ShuffleMode> _shuffleModeSubject = BehaviorSubject();
|
final BehaviorSubject<ShuffleMode> _shuffleModeSubject = BehaviorSubject();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -34,16 +40,13 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
ValueStream<LoopMode> get loopModeStream => _loopModeSubject.stream;
|
ValueStream<LoopMode> get loopModeStream => _loopModeSubject.stream;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValueStream<List<Song>> get songListStream => _songListSubject.stream;
|
ValueStream<List<Song>> get queueStream => _queueSubject.stream;
|
||||||
|
|
||||||
@override
|
|
||||||
ValueStream<List<QueueItem>> get queueStream => _queueSubject.stream;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValueStream<int> get currentIndexStream => _audioPlayerDataSource.currentIndexStream;
|
ValueStream<int> get currentIndexStream => _audioPlayerDataSource.currentIndexStream;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<Song> get currentSongStream => _audioPlayerDataSource.currentSongStream;
|
Stream<Song> get currentSongStream => _currentSongSubject.stream;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<PlaybackEvent> get playbackEventStream => _audioPlayerDataSource.playbackEventStream;
|
Stream<PlaybackEvent> get playbackEventStream => _audioPlayerDataSource.playbackEventStream;
|
||||||
|
@ -55,9 +58,9 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
Stream<Duration> get positionStream => _audioPlayerDataSource.positionStream;
|
Stream<Duration> get positionStream => _audioPlayerDataSource.positionStream;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> addToQueue(Song song) {
|
Future<void> addToQueue(Song song) async {
|
||||||
// TODO: implement addToQueue
|
_audioPlayerDataSource.addToQueue(song as SongModel);
|
||||||
throw UnimplementedError();
|
_queueSubject.add(_queueSubject.value + [song]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -66,10 +69,9 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> loadQueue({List<QueueItem> queue, int initialIndex}) async {
|
Future<void> loadQueue({List<Song> queue, int initialIndex}) async {
|
||||||
// _currentSongSubject.add(queue[initialIndex]);
|
// _currentSongSubject.add(queue[initialIndex]);
|
||||||
_queueSubject.add(queue);
|
_queueSubject.add(queue);
|
||||||
_songListSubject.add(queue.map((e) => e.song).toList());
|
|
||||||
// _currentIndexSubject.add(initialIndex);
|
// _currentIndexSubject.add(initialIndex);
|
||||||
|
|
||||||
await _audioPlayerDataSource.loadQueue(
|
await _audioPlayerDataSource.loadQueue(
|
||||||
|
@ -79,9 +81,15 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> moveQueueItem(int oldIndex, int newIndex) {
|
Future<void> moveQueueItem(int oldIndex, int newIndex) async {
|
||||||
// TODO: implement moveQueueItem
|
final _songList = _queueSubject.value.toList();
|
||||||
throw UnimplementedError();
|
|
||||||
|
_audioPlayerDataSource.moveQueueItem(oldIndex, newIndex);
|
||||||
|
|
||||||
|
final song = _songList.removeAt(oldIndex);
|
||||||
|
_songList.insert(newIndex, song);
|
||||||
|
|
||||||
|
_queueSubject.add(_songList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -104,9 +112,32 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> removeQueueIndex(int index) {
|
Future<void> playNext(Song song) async {
|
||||||
// TODO: implement removeQueueIndex
|
final index = currentIndexStream.value + 1;
|
||||||
throw UnimplementedError();
|
final _songList = _queueSubject.value;
|
||||||
|
|
||||||
|
_audioPlayerDataSource.playNext(song as SongModel);
|
||||||
|
_queueSubject.add(_songList.sublist(0, index) + [song] + _songList.sublist(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> removeQueueIndex(int index) async {
|
||||||
|
final _songList = _queueSubject.value;
|
||||||
|
|
||||||
|
_audioPlayerDataSource.removeQueueIndex(index);
|
||||||
|
|
||||||
|
_queueSubject.add(_songList.sublist(0, index) + _songList.sublist(index + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> replaceQueueAroundIndex({List<Song> before, List<Song> after, int index}) async {
|
||||||
|
_queueSubject.add(before + [_queueSubject.value[index]] + after);
|
||||||
|
|
||||||
|
await _audioPlayerDataSource.replaceQueueAroundIndex(
|
||||||
|
before: before.map((e) => e as SongModel).toList(),
|
||||||
|
after: after.map((e) => e as SongModel).toList(),
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -120,9 +151,8 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setIndex(int index) {
|
Future<void> seekToIndex(int index) async {
|
||||||
// TODO: implement setIndex
|
await _audioPlayerDataSource.seekToIndex(index);
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -141,4 +171,10 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
||||||
// TODO: implement stop
|
// TODO: implement stop
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _updateCurrentSong(List<Song> queue, int index) {
|
||||||
|
if (queue != null && index != null && index < queue.length) {
|
||||||
|
_currentSongSubject.add(queue[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue