diff --git a/src/lib/domain/modules/dynamic_queue.dart b/src/lib/domain/modules/dynamic_queue.dart index 0d85419..a894811 100644 --- a/src/lib/domain/modules/dynamic_queue.dart +++ b/src/lib/domain/modules/dynamic_queue.dart @@ -26,9 +26,14 @@ class DynamicQueue implements ManagedQueueInfo { final MusicDataRepository _musicDataRepository; + /// The queue as a list of Songs instead of QueueItems. List get queue => _queue.map((e) => e.song).toList(); + + /// The list of Songs still available for queue generation. + /// + /// This excludes songs that have already been queued. List get availableSongs => - (_availableSongs..where((element) => element.isAvailable)).map((e) => e.song).toList(); + _availableSongs.where((element) => element.isAvailable).map((e) => e.song).toList(); /// The queue generated so far from the [_availableSongs]. List _queue = []; @@ -431,10 +436,10 @@ class DynamicQueue implements ManagedQueueInfo { } int getNextNormalIndex(int index) { - if (index >= queue.length) return queue.length; + if (index >= _queue.length) return _queue.length; int i = index; - while (i < queue.length && _queue[i].source == QueueItemSource.added) { + while (i < _queue.length && _queue[i].source == QueueItemSource.added) { i++; } diff --git a/src/lib/system/repositories/audio_player_repository_impl.dart b/src/lib/system/repositories/audio_player_repository_impl.dart index b3dd2f2..adba87b 100644 --- a/src/lib/system/repositories/audio_player_repository_impl.dart +++ b/src/lib/system/repositories/audio_player_repository_impl.dart @@ -128,11 +128,12 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository { availableSongs, playable, ); - _queueSubject.add(_dynamicQueue.queue); + final queue = _dynamicQueue.queue; + _queueSubject.add(queue); await _audioPlayerDataSource.loadQueue( initialIndex: index, - queue: _dynamicQueue.queue.map((e) => e as SongModel).toList(), + queue: queue.map((e) => e as SongModel).toList(), ); } } @@ -154,11 +155,12 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository { keepIndex: keepInitialIndex, ); - _queueSubject.add(_dynamicQueue.queue); + final queue = _dynamicQueue.queue; + _queueSubject.add(queue); await _audioPlayerDataSource.loadQueue( initialIndex: _initialIndex, - queue: _dynamicQueue.queue.map((e) => e as SongModel).toList(), + queue: queue.map((e) => e as SongModel).toList(), ); } @@ -270,15 +272,14 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository { final splitIndex = await _dynamicQueue.reshuffleQueue(shuffleMode, currentIndex); _blockIndexUpdate = true; + final queue = _dynamicQueue.queue; _audioPlayerDataSource .replaceQueueAroundIndex( - index: currentIndex, - before: _dynamicQueue.queue.sublist(0, splitIndex).map((e) => e as SongModel).toList(), - after: _dynamicQueue.queue.sublist(splitIndex + 1).map((e) => e as SongModel).toList(), - ) - .then((_) { - _queueSubject.add(_dynamicQueue.queue); - }); + index: currentIndex, + before: queue.sublist(0, splitIndex).map((e) => e as SongModel).toList(), + after: queue.sublist(splitIndex + 1).map((e) => e as SongModel).toList(), + ) + .then((_) => _queueSubject.add(_dynamicQueue.queue)); } } @@ -300,16 +301,16 @@ class AudioPlayerRepositoryImpl implements AudioPlayerRepository { final blockLevel = calcBlockLevel(shuffleModeStream.value, playableStream.value); final queue = _dynamicQueue.queue; - final indecesToRemove = []; + final indicesToRemove = []; for (int i = 0; i < queue.length; i++) { final song = queue[i]; if (song.blockLevel > blockLevel) { if (oldQueue.firstWhere((e) => e.path == song.path).blockLevel != song.blockLevel) { - indecesToRemove.add(i); + indicesToRemove.add(i); } } } - if (indecesToRemove.isNotEmpty) _removeQueueIndices(indecesToRemove, false); + if (indicesToRemove.isNotEmpty) _removeQueueIndices(indicesToRemove, false); _queueSubject.add(_dynamicQueue.queue); } diff --git a/src/test/domain/modules/dynamic_queue_test.dart b/src/test/domain/modules/dynamic_queue_test.dart index b81e536..232ef13 100644 --- a/src/test/domain/modules/dynamic_queue_test.dart +++ b/src/test/domain/modules/dynamic_queue_test.dart @@ -1,14 +1,12 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; import 'package:mucke/domain/entities/playable.dart'; import 'package:mucke/domain/entities/queue_item.dart'; -import 'package:mucke/domain/entities/shuffle_mode.dart'; import 'package:mucke/domain/modules/dynamic_queue.dart'; import 'package:mucke/domain/repositories/music_data_repository.dart'; - +import '../../test_songs.dart'; @GenerateNiceMocks([MockSpec(), MockSpec()]) import 'dynamic_queue_test.mocks.dart'; @@ -32,10 +30,62 @@ void main() { // act sut.init(tQueue, tAvailableSongs, tPlayable); - + // assert expect(sut.playableStream.value, tPlayable); }, ); + + test( + 'should set queue', + () async { + // arrange + final tQueue = [ + QueueItem(song1, originalIndex: 0, isAvailable: true), + QueueItem(song2, originalIndex: 1, isAvailable: true), + QueueItem(song3, originalIndex: 2, isAvailable: true) + ]; + final tAvailableSongs = [ + QueueItem(song1, originalIndex: 0, isAvailable: true), + QueueItem(song2, originalIndex: 1, isAvailable: true), + QueueItem(song3, originalIndex: 2, isAvailable: true) + ]; + + final tPlayable = MockPlayable(); + + // act + sut.init(tQueue, tAvailableSongs, tPlayable); + + // assert + expect(sut.queueItemsStream.value, tQueue); + expect(sut.queue, [song1, song2, song3]); + }, + ); + + test( + 'should set available songs', + () async { + // arrange + final tQueue = [ + QueueItem(song1, originalIndex: 0, isAvailable: true), + QueueItem(song2, originalIndex: 1, isAvailable: true), + QueueItem(song3, originalIndex: 2, isAvailable: false) + ]; + final tAvailableSongs = [ + QueueItem(song1, originalIndex: 0, isAvailable: true), + QueueItem(song2, originalIndex: 1, isAvailable: true), + QueueItem(song3, originalIndex: 2, isAvailable: false) + ]; + + final tPlayable = MockPlayable(); + + // act + sut.init(tQueue, tAvailableSongs, tPlayable); + + // assert + expect(sut.availableSongsStream.value, tAvailableSongs); + expect(sut.availableSongs, [song1, song2]); + }, + ); }); -} \ No newline at end of file +} diff --git a/src/test/test_songs.dart b/src/test/test_songs.dart new file mode 100644 index 0000000..2313e56 --- /dev/null +++ b/src/test/test_songs.dart @@ -0,0 +1,52 @@ +import 'package:mucke/domain/entities/song.dart'; + +final Song song1 = Song( + album: 'Sample Album', + albumId: 1, + artist: 'Sample Artist', + blockLevel: 3, + duration: const Duration(minutes: 3, seconds: 45), + path: '/path/to/song1.mp3', + title: 'Sample Song 1', + likeCount: 1, + playCount: 350, + discNumber: 1, + next: false, + previous: false, + timeAdded: DateTime(1990), + trackNumber: 5, +); + +final Song song2 = Song( + album: 'Sample Album 2', + albumId: 2, + artist: 'Sample Artist 2', + blockLevel: 2, + duration: const Duration(minutes: 4, seconds: 10), + path: '/path/to/song2.mp3', + title: 'Sample Song 2', + likeCount: 3, + playCount: 420, + discNumber: 1, + next: false, + previous: false, + timeAdded: DateTime(2000), + trackNumber: 2, +); + +final Song song3 = Song( + album: 'Sample Album 1', + albumId: 1, + artist: 'Sample Artist 1', + blockLevel: 0, + duration: const Duration(minutes: 5, seconds: 20), + path: '/path/to/song3.mp3', + title: 'Sample Song 3', + likeCount: 0, + playCount: 150, + discNumber: 2, + next: false, + previous: false, + timeAdded: DateTime(2010), + trackNumber: 7, +);