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 '../repositories/music_data_repository.dart';
|
||||
|
||||
class QueueGenerationModule {
|
||||
QueueGenerationModule(this._musicDataRepository);
|
||||
class QueueManagerModule {
|
||||
QueueManagerModule(this._musicDataRepository);
|
||||
|
||||
List<QueueItem> get queue => _queue;
|
||||
|
||||
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,
|
||||
List<Song> songs,
|
||||
int startIndex,
|
||||
) 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) {
|
||||
case ShuffleMode.none:
|
||||
queue = _generateNormalQueue(songs);
|
||||
break;
|
||||
return _generateNormalQueue(songs);
|
||||
case ShuffleMode.standard:
|
||||
queue = _generateShuffleQueue(songs, startIndex);
|
||||
break;
|
||||
return _generateShuffleQueue(songs, startIndex);
|
||||
case ShuffleMode.plus:
|
||||
queue = await _generateShufflePlusQueue(songs, startIndex);
|
||||
return await _generateShufflePlusQueue(songs, startIndex);
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
List<QueueItem> _generateNormalQueue(List<Song> songs) {
|
|
@ -3,7 +3,6 @@ import 'package:rxdart/rxdart.dart';
|
|||
import '../entities/event.dart';
|
||||
import '../entities/loop_mode.dart';
|
||||
import '../entities/playback_event.dart';
|
||||
import '../entities/queue_item.dart';
|
||||
import '../entities/shuffle_mode.dart';
|
||||
import '../entities/song.dart';
|
||||
|
||||
|
@ -12,8 +11,7 @@ abstract class AudioPlayerInfoRepository {
|
|||
|
||||
ValueStream<ShuffleMode> get shuffleModeStream;
|
||||
ValueStream<LoopMode> get loopModeStream;
|
||||
ValueStream<List<Song>> get songListStream;
|
||||
ValueStream<List<QueueItem>> get queueStream;
|
||||
ValueStream<List<Song>> get queueStream;
|
||||
|
||||
ValueStream<int> get currentIndexStream;
|
||||
Stream<Song> get currentSongStream;
|
||||
|
@ -28,14 +26,16 @@ abstract class AudioPlayerRepository extends AudioPlayerInfoRepository {
|
|||
Future<void> stop();
|
||||
Future<bool> seekToNext();
|
||||
Future<void> seekToPrevious();
|
||||
Future<void> seekToIndex(int index);
|
||||
Future<void> dispose();
|
||||
|
||||
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> playNext(Song song);
|
||||
Future<void> moveQueueItem(int oldIndex, int newIndex);
|
||||
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.
|
||||
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 '../modules/queue_generator.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';
|
||||
|
@ -16,27 +17,32 @@ class PlaySongs {
|
|||
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||
final PlayerStateRepository _playerStateRepository;
|
||||
|
||||
final QueueGenerationModule _queueGenerationModule;
|
||||
final QueueManagerModule _queueGenerationModule;
|
||||
|
||||
Future<void> call({List<Song> songs, int initialIndex}) async {
|
||||
if (0 <= initialIndex && initialIndex < songs.length) {
|
||||
// _audioPlayerRepository.playSong(songs[initialIndex]);
|
||||
|
||||
final queueItems = await _queueGenerationModule.generateQueue(
|
||||
_audioPlayerRepository.shuffleModeStream.value,
|
||||
final shuffleMode = _audioPlayerRepository.shuffleModeStream.value;
|
||||
|
||||
await _queueGenerationModule.setQueue(
|
||||
shuffleMode,
|
||||
songs,
|
||||
initialIndex,
|
||||
);
|
||||
|
||||
final queueItems = _queueGenerationModule.queue;
|
||||
final songList = queueItems.map((e) => e.song).toList();
|
||||
|
||||
await _audioPlayerRepository.loadQueue(
|
||||
initialIndex: initialIndex,
|
||||
queue: queueItems,
|
||||
initialIndex: shuffleMode == ShuffleMode.none ? initialIndex : 0,
|
||||
queue: songList,
|
||||
);
|
||||
_audioPlayerRepository.play();
|
||||
|
||||
_platformIntegrationRepository.setCurrentSong(songs[initialIndex]);
|
||||
// _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/song.dart';
|
||||
import '../modules/queue_generator.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';
|
||||
|
@ -12,53 +9,32 @@ class SetShuffleMode {
|
|||
this._audioPlayerRepository,
|
||||
this._platformIntegrationRepository,
|
||||
this._playerStateRepository,
|
||||
this._queueGenerationModule,
|
||||
this._queueManagerModule,
|
||||
);
|
||||
|
||||
final AudioPlayerRepository _audioPlayerRepository;
|
||||
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||
final PlayerStateRepository _playerStateRepository;
|
||||
|
||||
final QueueGenerationModule _queueGenerationModule;
|
||||
final QueueManagerModule _queueManagerModule;
|
||||
|
||||
Future<void> call(ShuffleMode shuffleMode) async {
|
||||
// _audioPlayerRepository.playSong(songs[initialIndex]);
|
||||
|
||||
_audioPlayerRepository.setShuffleMode(shuffleMode);
|
||||
|
||||
final queue = _audioPlayerRepository.queueStream.value;
|
||||
final currentIndex = _audioPlayerRepository.currentIndexStream.value;
|
||||
final originalIndex = _queueManagerModule.queue[currentIndex].originalIndex;
|
||||
|
||||
final QueueItem currentQueueItem = queue[currentIndex];
|
||||
final int index = currentQueueItem.originalIndex;
|
||||
await _queueManagerModule.reshuffleQueue(shuffleMode, currentIndex);
|
||||
final queue = _queueManagerModule.queue;
|
||||
|
||||
// WAS LETZTE GEDANKE?
|
||||
// _inputQueue ist die originale Song Liste aus playSongs o.ä. BEVOR der QueueGenerator drüber läuft
|
||||
final songList = queue.map((e) => e.song).toList();
|
||||
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);
|
||||
// // 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);
|
||||
_platformIntegrationRepository.setQueue(songList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:math';
|
|||
|
||||
import '../entities/shuffle_mode.dart';
|
||||
import '../entities/song.dart';
|
||||
import '../modules/queue_generator.dart';
|
||||
import '../modules/queue_manager.dart';
|
||||
import '../repositories/audio_player_repository.dart';
|
||||
import '../repositories/music_data_repository.dart';
|
||||
import '../repositories/persistent_player_state_repository.dart';
|
||||
|
@ -24,7 +24,7 @@ class ShuffleAll {
|
|||
final PlatformIntegrationRepository _platformIntegrationRepository;
|
||||
final PlayerStateRepository _playerStateRepository;
|
||||
|
||||
final QueueGenerationModule _queueGenerationModule;
|
||||
final QueueManagerModule _queueGenerationModule;
|
||||
|
||||
Future<void> call() async {
|
||||
final List<Song> songs = await _musicDataRepository.songStream.first;
|
||||
|
@ -33,20 +33,23 @@ class ShuffleAll {
|
|||
|
||||
_audioPlayerRepository.setShuffleMode(SHUFFLE_MODE);
|
||||
|
||||
final queueItems = await _queueGenerationModule.generateQueue(
|
||||
await _queueGenerationModule.setQueue(
|
||||
SHUFFLE_MODE,
|
||||
songs,
|
||||
index,
|
||||
);
|
||||
|
||||
final queueItems = _queueGenerationModule.queue;
|
||||
final songList = queueItems.map((e) => e.song).toList();
|
||||
|
||||
await _audioPlayerRepository.loadQueue(
|
||||
initialIndex: 0,
|
||||
queue: queueItems,
|
||||
queue: songList,
|
||||
);
|
||||
_audioPlayerRepository.play();
|
||||
|
||||
_platformIntegrationRepository.setCurrentSong(songs[index]);
|
||||
// _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/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/music_data_modifier_repository.dart';
|
||||
import 'domain/repositories/music_data_repository.dart';
|
||||
import 'domain/repositories/persistent_player_state_repository.dart';
|
||||
import 'domain/repositories/platform_integration_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/move_queue_item.dart';
|
||||
import 'domain/usecases/pause.dart';
|
||||
import 'domain/usecases/play.dart';
|
||||
import 'domain/usecases/play_next.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_previous.dart';
|
||||
import 'domain/usecases/set_current_song.dart';
|
||||
import 'domain/usecases/set_loop_mode.dart';
|
||||
import 'domain/usecases/set_shuffle_mode.dart';
|
||||
import 'domain/usecases/shuffle_all.dart';
|
||||
import 'domain/usecases/update_database.dart';
|
||||
import 'presentation/state/audio_store.dart';
|
||||
|
@ -64,12 +70,18 @@ Future<void> setupGetIt() async {
|
|||
() {
|
||||
final audioStore = AudioStore(
|
||||
audioPlayerInfoRepository: getIt(),
|
||||
addToQueue: getIt(),
|
||||
moveQueueItem: getIt(),
|
||||
pause: getIt(),
|
||||
play: getIt(),
|
||||
playNext: getIt(),
|
||||
playSongs: getIt(),
|
||||
removeQueueIndex: getIt(),
|
||||
seekToIndex: getIt(),
|
||||
seekToNext: getIt(),
|
||||
seekToPrevious: getIt(),
|
||||
setLoopMode: getIt(),
|
||||
setShuffleMode: getIt(),
|
||||
shuffleAll: getIt(),
|
||||
);
|
||||
return audioStore;
|
||||
|
@ -83,11 +95,27 @@ Future<void> setupGetIt() async {
|
|||
);
|
||||
|
||||
// use cases
|
||||
getIt.registerLazySingleton<AddToQueue>(
|
||||
() => AddToQueue(
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<HandlePlaybackEvent>(
|
||||
() => HandlePlaybackEvent(
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<MoveQueueItem>(
|
||||
() => MoveQueueItem(
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<Pause>(
|
||||
() => Pause(
|
||||
getIt(),
|
||||
|
@ -98,6 +126,14 @@ Future<void> setupGetIt() async {
|
|||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<PlayNext>(
|
||||
() => PlayNext(
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<PlaySongs>(
|
||||
() => PlaySongs(
|
||||
getIt(),
|
||||
|
@ -106,6 +142,19 @@ Future<void> setupGetIt() async {
|
|||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<RemoveQueueIndex>(
|
||||
() => RemoveQueueIndex(
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<SeekToIndex>(
|
||||
() => SeekToIndex(
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<SeekToNext>(
|
||||
() => SeekToNext(
|
||||
getIt(),
|
||||
|
@ -126,6 +175,14 @@ Future<void> setupGetIt() async {
|
|||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<SetShuffleMode>(
|
||||
() => SetShuffleMode(
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
getIt.registerLazySingleton<ShuffleAll>(
|
||||
() => ShuffleAll(
|
||||
getIt(),
|
||||
|
@ -142,8 +199,8 @@ Future<void> setupGetIt() async {
|
|||
);
|
||||
|
||||
// modules
|
||||
getIt.registerLazySingleton<QueueGenerationModule>(
|
||||
() => QueueGenerationModule(
|
||||
getIt.registerLazySingleton<QueueManagerModule>(
|
||||
() => QueueManagerModule(
|
||||
getIt(),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -108,6 +108,13 @@ class AlbumDetailsPage extends StatelessWidget {
|
|||
return Container(
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: const Text('Play next'),
|
||||
onTap: () {
|
||||
audioStore.playNext(song);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Add to queue'),
|
||||
onTap: () {
|
||||
|
|
|
@ -47,7 +47,7 @@ class QueuePage extends StatelessWidget {
|
|||
subtitle: '${song.artist}',
|
||||
albumArtPath: song.albumArtPath,
|
||||
highlight: index == activeIndex,
|
||||
onTap: () => audioStore.setIndex(index),
|
||||
onTap: () => audioStore.seekToIndex(index),
|
||||
),
|
||||
onDismissed: (direction) {
|
||||
audioStore.removeQueueIndex(index);
|
||||
|
|
|
@ -77,6 +77,13 @@ class _SongsPageState extends State<SongsPage>
|
|||
return Container(
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: const Text('Play next'),
|
||||
onTap: () {
|
||||
audioStore.playNext(song);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Add to queue'),
|
||||
onTap: () {
|
||||
|
|
|
@ -7,45 +7,77 @@ import '../../domain/entities/loop_mode.dart';
|
|||
import '../../domain/entities/shuffle_mode.dart';
|
||||
import '../../domain/entities/song.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/play.dart';
|
||||
import '../../domain/usecases/play_next.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_previous.dart';
|
||||
import '../../domain/usecases/set_loop_mode.dart';
|
||||
import '../../domain/usecases/set_shuffle_mode.dart';
|
||||
import '../../domain/usecases/shuffle_all.dart';
|
||||
|
||||
part 'audio_store.g.dart';
|
||||
|
||||
class AudioStore extends _AudioStore with _$AudioStore {
|
||||
AudioStore({
|
||||
@required AddToQueue addToQueue,
|
||||
@required MoveQueueItem moveQueueItem,
|
||||
@required Pause pause,
|
||||
@required Play play,
|
||||
@required PlayNext playNext,
|
||||
@required PlaySongs playSongs,
|
||||
@required RemoveQueueIndex removeQueueIndex,
|
||||
@required SeekToIndex seekToIndex,
|
||||
@required SeekToNext seekToNext,
|
||||
@required SeekToPrevious seekToPrevious,
|
||||
@required SetLoopMode setLoopMode,
|
||||
@required SetShuffleMode setShuffleMode,
|
||||
@required ShuffleAll shuffleAll,
|
||||
@required AudioPlayerInfoRepository audioPlayerInfoRepository,
|
||||
}) : super(playSongs, audioPlayerInfoRepository, pause, play, seekToNext, seekToPrevious,
|
||||
setLoopMode, shuffleAll);
|
||||
}) : super(
|
||||
addToQueue,
|
||||
moveQueueItem,
|
||||
playSongs,
|
||||
audioPlayerInfoRepository,
|
||||
pause,
|
||||
play,
|
||||
playNext,
|
||||
removeQueueIndex,
|
||||
seekToIndex,
|
||||
seekToNext,
|
||||
seekToPrevious,
|
||||
setLoopMode,
|
||||
setShuffleMode,
|
||||
shuffleAll,
|
||||
);
|
||||
}
|
||||
|
||||
abstract class _AudioStore with Store {
|
||||
_AudioStore(
|
||||
this._addToQueue,
|
||||
this._moveQueueItem,
|
||||
this._playSongs,
|
||||
this._audioPlayerInfoRepository,
|
||||
this._pause,
|
||||
this._play,
|
||||
this._playNext,
|
||||
this._removeQueueIndex,
|
||||
this._seekToIndex,
|
||||
this._seekToNext,
|
||||
this._seekToPrevious,
|
||||
this._setLoopMode,
|
||||
this._setShuffleMode,
|
||||
this._shuffleAll,
|
||||
) {
|
||||
currentPositionStream = _audioPlayerInfoRepository.positionStream
|
||||
.asObservable(initialValue: const Duration(seconds: 0));
|
||||
|
||||
queueStream = _audioPlayerInfoRepository.songListStream.asObservable();
|
||||
queueStream = _audioPlayerInfoRepository.queueStream.asObservable();
|
||||
|
||||
queueIndexStream = _audioPlayerInfoRepository.currentIndexStream.asObservable();
|
||||
|
||||
|
@ -60,12 +92,18 @@ abstract class _AudioStore with Store {
|
|||
|
||||
final AudioPlayerInfoRepository _audioPlayerInfoRepository;
|
||||
|
||||
final AddToQueue _addToQueue;
|
||||
final MoveQueueItem _moveQueueItem;
|
||||
final Pause _pause;
|
||||
final Play _play;
|
||||
final PlayNext _playNext;
|
||||
final PlaySongs _playSongs;
|
||||
final RemoveQueueIndex _removeQueueIndex;
|
||||
final SeekToIndex _seekToIndex;
|
||||
final SeekToNext _seekToNext;
|
||||
final SeekToPrevious _seekToPrevious;
|
||||
final SetLoopMode _setLoopMode;
|
||||
final SetShuffleMode _setShuffleMode;
|
||||
final ShuffleAll _shuffleAll;
|
||||
|
||||
@observable
|
||||
|
@ -77,6 +115,8 @@ abstract class _AudioStore with Store {
|
|||
@observable
|
||||
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
|
||||
ObservableStream<List<Song>> queueStream;
|
||||
|
||||
|
@ -109,12 +149,12 @@ abstract class _AudioStore with Store {
|
|||
_seekToPrevious();
|
||||
}
|
||||
|
||||
Future<void> setIndex(int index) async {
|
||||
// _audioInterface.setIndex(index);
|
||||
Future<void> seekToIndex(int index) async {
|
||||
_seekToIndex(index);
|
||||
}
|
||||
|
||||
Future<void> setShuffleMode(ShuffleMode shuffleMode) async {
|
||||
// _audioInterface.setShuffleMode(shuffleMode);
|
||||
_setShuffleMode(shuffleMode);
|
||||
}
|
||||
|
||||
Future<void> setLoopMode(LoopMode loopMode) async {
|
||||
|
@ -126,15 +166,19 @@ abstract class _AudioStore with Store {
|
|||
}
|
||||
|
||||
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 {
|
||||
// _audioInterface.moveQueueItem(oldIndex, newIndex);
|
||||
_moveQueueItem(oldIndex, newIndex);
|
||||
}
|
||||
|
||||
Future<void> removeQueueIndex(int index) async {
|
||||
// _audioInterface.removeQueueIndex(index);
|
||||
_removeQueueIndex(index);
|
||||
}
|
||||
|
||||
Future<void> playAlbum(Album album) async {
|
||||
|
|
|
@ -18,8 +18,6 @@ class AlbumArt extends StatelessWidget {
|
|||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(2.0),
|
||||
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)),
|
||||
],
|
||||
),
|
||||
|
@ -33,22 +31,6 @@ class AlbumArt extends StatelessWidget {
|
|||
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(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
|
|
|
@ -6,7 +6,7 @@ import '../models/song_model.dart';
|
|||
|
||||
abstract class AudioPlayerDataSource {
|
||||
ValueStream<int> get currentIndexStream;
|
||||
ValueStream<SongModel> get currentSongStream;
|
||||
// ValueStream<SongModel> get currentSongStream;
|
||||
Stream<PlaybackEventModel> get playbackEventStream;
|
||||
ValueStream<bool> get playingStream;
|
||||
ValueStream<Duration> get positionStream;
|
||||
|
@ -21,10 +21,10 @@ abstract class AudioPlayerDataSource {
|
|||
Future<void> loadQueue({List<SongModel> queue, int initialIndex});
|
||||
Future<void> addToQueue(SongModel song);
|
||||
Future<void> moveQueueItem(int oldIndex, int newIndex);
|
||||
Future<void> playNext(SongModel song);
|
||||
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> playSongList(List<SongModel> songs, int startIndex);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:just_audio/just_audio.dart' as ja;
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
@ -8,24 +10,25 @@ import '../models/playback_event_model.dart';
|
|||
import '../models/song_model.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 {
|
||||
AudioPlayerDataSourceImpl(this._audioPlayer) {
|
||||
_audioPlayer.currentIndexStream.listen((event) {
|
||||
_log.info('currentIndex: $event');
|
||||
_currentIndexSubject.add(event);
|
||||
if (_queue != null && event != null && event < _queue.length) {
|
||||
_currentSongSubject.add(_queue[event]);
|
||||
_audioPlayer.currentIndexStream.listen((index) async {
|
||||
_log.info('currentIndexSteam.listen: $index');
|
||||
if (!await _updateLoadedQueue(index)) {
|
||||
_updateCurrentIndex(index);
|
||||
}
|
||||
});
|
||||
|
||||
_audioPlayer.playingStream.listen((event) {
|
||||
_log.info('playing: $event');
|
||||
_playingSubject.add(event);
|
||||
});
|
||||
_audioPlayer.playingStream.listen((event) => _playingSubject.add(event));
|
||||
|
||||
_audioPlayer.positionStream.listen((event) {
|
||||
_positionSubject.add(event);
|
||||
});
|
||||
_audioPlayer.positionStream.listen((event) => _positionSubject.add(event));
|
||||
|
||||
_playbackEventModelStream = Rx.combineLatest2<ja.PlaybackEvent, bool, PlaybackEventModel>(
|
||||
_audioPlayer.playbackEventStream,
|
||||
|
@ -40,29 +43,43 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
|||
static final _log = Logger('AudioPlayer');
|
||||
|
||||
final BehaviorSubject<int> _currentIndexSubject = BehaviorSubject();
|
||||
final BehaviorSubject<SongModel> _currentSongSubject = BehaviorSubject();
|
||||
final BehaviorSubject<PlaybackEventModel> _playbackEventSubject = BehaviorSubject();
|
||||
final BehaviorSubject<bool> _playingSubject = BehaviorSubject();
|
||||
final BehaviorSubject<Duration> _positionSubject = BehaviorSubject();
|
||||
|
||||
Stream<PlaybackEventModel> _playbackEventModelStream;
|
||||
List<SongModel> _queue;
|
||||
int _loadStartIndex;
|
||||
int _loadEndIndex;
|
||||
|
||||
void _setQueue(List<SongModel> queue, {int index}) {
|
||||
_queue = queue;
|
||||
if (index != null) {
|
||||
_currentSongSubject.add(_queue[index]);
|
||||
} else if (_currentIndexSubject.value != null) {
|
||||
_currentSongSubject.add(_queue[_currentIndexSubject.value]);
|
||||
set loadStartIndex(int i) {
|
||||
_loadStartIndex = i;
|
||||
_log.info('loadStartIndex <- $i');
|
||||
// _updateCurrentIndex(_audioPlayer.currentIndex);
|
||||
}
|
||||
|
||||
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
|
||||
ValueStream<int> get currentIndexStream => _currentIndexSubject.stream;
|
||||
|
||||
@override
|
||||
ValueStream<SongModel> get currentSongStream => _currentSongSubject.stream;
|
||||
|
||||
@override
|
||||
Stream<PlaybackEventModel> get playbackEventStream => _playbackEventModelStream;
|
||||
|
||||
|
@ -75,7 +92,6 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
|||
@override
|
||||
Future<void> dispose() async {
|
||||
await _currentIndexSubject.close();
|
||||
await _currentSongSubject.close();
|
||||
await _playbackEventSubject.close();
|
||||
await _positionSubject.close();
|
||||
await _audioPlayer.dispose();
|
||||
|
@ -86,12 +102,18 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
|||
if (queue == null || initialIndex == null || initialIndex >= queue.length) {
|
||||
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);
|
||||
_audioPlayer.setAudioSource(_audioSource, initialIndex: initialIndex);
|
||||
final smallQueue = queue.sublist(loadStartIndex, loadEndIndex);
|
||||
|
||||
_audioSource = _songModelsToAudioSource(smallQueue);
|
||||
|
||||
// _loadStartIndex.add(loadStartIndex);
|
||||
// _loadEndIndex.add(loadEndIndex);
|
||||
_audioPlayer.setAudioSource(_audioSource, initialIndex: initialIndex - loadStartIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -104,26 +126,6 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
|||
_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
|
||||
Future<bool> seekToNext() async {
|
||||
final result = _audioPlayer.hasNext;
|
||||
|
@ -141,7 +143,7 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> setIndex(int index) async {
|
||||
Future<void> seekToIndex(int index) async {
|
||||
await _audioPlayer.seek(const Duration(seconds: 0), index: index);
|
||||
}
|
||||
|
||||
|
@ -153,43 +155,43 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
|||
@override
|
||||
Future<void> addToQueue(SongModel song) async {
|
||||
await _audioSource.add(ja.AudioSource.uri(Uri.file(song.path)));
|
||||
// _queue.add(QueueItemModel(song, originalIndex: -1, type: QueueItemType.added));
|
||||
// _queueSubject.add(_queue);
|
||||
_queue.add(song);
|
||||
}
|
||||
|
||||
@override
|
||||
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);
|
||||
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
|
||||
Future<void> removeQueueIndex(int index) async {
|
||||
// _queue.removeAt(index);
|
||||
// _queueSubject.add(_queue);
|
||||
await _audioSource.removeAt(index);
|
||||
_queue.removeAt(index);
|
||||
}
|
||||
|
||||
// @override
|
||||
// Future<void> setShuffleMode(ShuffleMode shuffleMode, bool updateQueue) async {
|
||||
// _log.info('setShuffleMode: $shuffleMode');
|
||||
// if (shuffleMode == null) return;
|
||||
// _shuffleModeSubject.add(shuffleMode);
|
||||
@override
|
||||
Future<void> replaceQueueAroundIndex(
|
||||
{List<SongModel> before, List<SongModel> after, int index}) async {
|
||||
_queue = before + [_queue[index]] + after;
|
||||
|
||||
// if (updateQueue) {
|
||||
// final QueueItem currentQueueItem = _queue[_currentIndexSubject.value];
|
||||
// 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 _before = _songModelsToAudioSource(before);
|
||||
final _after = _songModelsToAudioSource(after);
|
||||
|
||||
// final newQueue = _songModelsToAudioSource(songModelQueue);
|
||||
// _updateQueue(newQueue, currentQueueItem);
|
||||
// }
|
||||
// }
|
||||
await _audioSource.removeRange(0, index);
|
||||
await _audioSource.removeRange(1, _audioSource.length);
|
||||
|
||||
await _audioSource.insertAll(0, _before.children);
|
||||
await _audioSource.addAll(_after.children);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLoopMode(LoopMode loopMode) async {
|
||||
|
@ -203,32 +205,117 @@ class AudioPlayerDataSourceImpl implements AudioPlayerDataSource {
|
|||
);
|
||||
}
|
||||
|
||||
// Future<void> _updateQueue(
|
||||
// ja.ConcatenatingAudioSource newQueue, QueueItem currentQueueItem) async {
|
||||
// final int index = currentQueueItem.originalIndex;
|
||||
/// extend the loaded audiosource, when seeking to previous/next
|
||||
Future<bool> _updateLoadedQueue(int newIndex) async {
|
||||
_log.info('updateLoadedQueue: $newIndex');
|
||||
_log.info('[$loadStartIndex, $loadEndIndex]');
|
||||
|
||||
// _audioSource.removeRange(0, _currentIndexSubject.value);
|
||||
// _audioSource.removeRange(1, _audioSource.length);
|
||||
if (loadStartIndex == null || loadEndIndex == null || newIndex == null) return false;
|
||||
|
||||
// if (_shuffleModeSubject.value == ShuffleMode.none) {
|
||||
// switch (currentQueueItem.type) {
|
||||
// case QueueItemType.added:
|
||||
// case QueueItemType.standard:
|
||||
// await _audioSource.insertAll(0, newQueue.children.sublist(0, index));
|
||||
// _audioSource.addAll(newQueue.children.sublist(index + 1));
|
||||
// break;
|
||||
// case QueueItemType.predecessor:
|
||||
// await _audioSource.insertAll(0, newQueue.children.sublist(0, index));
|
||||
// _audioSource.addAll(newQueue.children.sublist(index));
|
||||
// break;
|
||||
// case QueueItemType.successor:
|
||||
// await _audioSource.insertAll(0, newQueue.children.sublist(0, index + 1));
|
||||
// _audioSource.addAll(newQueue.children.sublist(index + 1));
|
||||
// break;
|
||||
// }
|
||||
// _currentIndexSubject.add(index);
|
||||
// } else {
|
||||
// _audioSource.addAll(newQueue.children.sublist(1));
|
||||
// }
|
||||
// }
|
||||
if (loadStartIndex == loadEndIndex || (loadStartIndex == 0 && loadEndIndex == _queue.length))
|
||||
return false;
|
||||
|
||||
if (loadStartIndex < loadEndIndex) {
|
||||
_log.info('base case');
|
||||
return await _updateLoadedQueueBaseCase(newIndex);
|
||||
} else {
|
||||
_log.info('inverted case');
|
||||
return await _updateLoadedQueueInverted(newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _updateLoadedQueueBaseCase(int newIndex) async {
|
||||
if (newIndex < LOAD_INTERVAL) {
|
||||
// nearing the start of the loaded songs
|
||||
if (loadStartIndex > 0) {
|
||||
// load the song previous to the already loaded songs
|
||||
_log.info('loadStartIndex--');
|
||||
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/playback_event.dart';
|
||||
import '../../domain/entities/queue_item.dart';
|
||||
import '../../domain/entities/shuffle_mode.dart';
|
||||
import '../../domain/entities/song.dart';
|
||||
import '../../domain/repositories/audio_player_repository.dart';
|
||||
|
@ -13,15 +12,22 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
AudioPlayerRepositoryImpl(this._audioPlayerDataSource) {
|
||||
_shuffleModeSubject.add(ShuffleMode.none);
|
||||
_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 BehaviorSubject<int> _currentIndexSubject = BehaviorSubject();
|
||||
// final BehaviorSubject<Song> _currentSongSubject = BehaviorSubject<Song>();
|
||||
final BehaviorSubject<Song> _currentSongSubject = BehaviorSubject<Song>();
|
||||
final BehaviorSubject<LoopMode> _loopModeSubject = BehaviorSubject();
|
||||
final BehaviorSubject<List<Song>> _songListSubject = BehaviorSubject();
|
||||
final BehaviorSubject<List<QueueItem>> _queueSubject = BehaviorSubject();
|
||||
final BehaviorSubject<List<Song>> _queueSubject = BehaviorSubject();
|
||||
final BehaviorSubject<ShuffleMode> _shuffleModeSubject = BehaviorSubject();
|
||||
|
||||
@override
|
||||
|
@ -34,16 +40,13 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
ValueStream<LoopMode> get loopModeStream => _loopModeSubject.stream;
|
||||
|
||||
@override
|
||||
ValueStream<List<Song>> get songListStream => _songListSubject.stream;
|
||||
|
||||
@override
|
||||
ValueStream<List<QueueItem>> get queueStream => _queueSubject.stream;
|
||||
ValueStream<List<Song>> get queueStream => _queueSubject.stream;
|
||||
|
||||
@override
|
||||
ValueStream<int> get currentIndexStream => _audioPlayerDataSource.currentIndexStream;
|
||||
|
||||
@override
|
||||
Stream<Song> get currentSongStream => _audioPlayerDataSource.currentSongStream;
|
||||
Stream<Song> get currentSongStream => _currentSongSubject.stream;
|
||||
|
||||
@override
|
||||
Stream<PlaybackEvent> get playbackEventStream => _audioPlayerDataSource.playbackEventStream;
|
||||
|
@ -55,9 +58,9 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
Stream<Duration> get positionStream => _audioPlayerDataSource.positionStream;
|
||||
|
||||
@override
|
||||
Future<void> addToQueue(Song song) {
|
||||
// TODO: implement addToQueue
|
||||
throw UnimplementedError();
|
||||
Future<void> addToQueue(Song song) async {
|
||||
_audioPlayerDataSource.addToQueue(song as SongModel);
|
||||
_queueSubject.add(_queueSubject.value + [song]);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -66,10 +69,9 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> loadQueue({List<QueueItem> queue, int initialIndex}) async {
|
||||
Future<void> loadQueue({List<Song> queue, int initialIndex}) async {
|
||||
// _currentSongSubject.add(queue[initialIndex]);
|
||||
_queueSubject.add(queue);
|
||||
_songListSubject.add(queue.map((e) => e.song).toList());
|
||||
// _currentIndexSubject.add(initialIndex);
|
||||
|
||||
await _audioPlayerDataSource.loadQueue(
|
||||
|
@ -79,9 +81,15 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> moveQueueItem(int oldIndex, int newIndex) {
|
||||
// TODO: implement moveQueueItem
|
||||
throw UnimplementedError();
|
||||
Future<void> moveQueueItem(int oldIndex, int newIndex) async {
|
||||
final _songList = _queueSubject.value.toList();
|
||||
|
||||
_audioPlayerDataSource.moveQueueItem(oldIndex, newIndex);
|
||||
|
||||
final song = _songList.removeAt(oldIndex);
|
||||
_songList.insert(newIndex, song);
|
||||
|
||||
_queueSubject.add(_songList);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -104,9 +112,32 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> removeQueueIndex(int index) {
|
||||
// TODO: implement removeQueueIndex
|
||||
throw UnimplementedError();
|
||||
Future<void> playNext(Song song) async {
|
||||
final index = currentIndexStream.value + 1;
|
||||
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
|
||||
|
@ -120,9 +151,8 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> setIndex(int index) {
|
||||
// TODO: implement setIndex
|
||||
throw UnimplementedError();
|
||||
Future<void> seekToIndex(int index) async {
|
||||
await _audioPlayerDataSource.seekToIndex(index);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -141,4 +171,10 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository {
|
|||
// TODO: implement stop
|
||||
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