diff --git a/src/lib/presentation/pages/currently_playing.dart b/src/lib/presentation/pages/currently_playing.dart index d80e505..43d2613 100644 --- a/src/lib/presentation/pages/currently_playing.dart +++ b/src/lib/presentation/pages/currently_playing.dart @@ -2,11 +2,11 @@ import 'package:fimber/fimber.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:get_it/get_it.dart'; +import 'package:mucke/presentation/widgets/album_art_swipe.dart'; import '../../domain/entities/song.dart'; import '../state/audio_store.dart'; import '../theming.dart'; -import '../widgets/album_art.dart'; import '../widgets/album_background.dart'; import '../widgets/currently_playing_header.dart'; import '../widgets/playback_control.dart'; @@ -30,9 +30,9 @@ class CurrentlyPlayingPage extends StatelessWidget { body: SafeArea( child: GestureDetector( onVerticalDragEnd: (dragEndDetails) { - if (dragEndDetails.primaryVelocity! < 0) { + if (dragEndDetails.primaryVelocity! < -1) { _openQueue(context); - } else if (dragEndDetails.primaryVelocity! > 0) { + } else if (dragEndDetails.primaryVelocity! > 1) { Navigator.pop(context); } }, @@ -40,7 +40,9 @@ class CurrentlyPlayingPage extends StatelessWidget { builder: (BuildContext context) { _log.d('Observer.build'); final Song? song = audioStore.currentSongStream.value; + final int? queueIndex = audioStore.queueIndexStream.value; if (song == null) return Container(); + if (queueIndex == null) return Container(); return Stack( children: [ @@ -70,8 +72,8 @@ class CurrentlyPlayingPage extends StatelessWidget { horizontal: 8.0, vertical: 0.0, ), - child: AlbumArt( - song: song, + child: AlbumArtSwipe( + queueIndex: queueIndex, ), ), ), diff --git a/src/lib/presentation/state/audio_store.dart b/src/lib/presentation/state/audio_store.dart index 5c26f8e..80959fe 100644 --- a/src/lib/presentation/state/audio_store.dart +++ b/src/lib/presentation/state/audio_store.dart @@ -55,10 +55,12 @@ abstract class _AudioStore with Store { this._playSmartList, this._playPlaylist, this._seekToNext, - this._shuffleAll, this._playPlayable, + this._shuffleAll, + this._playPlayable, ) { _audioPlayerRepository.managedQueueInfo.queueItemsStream.listen(_setQueue); - _audioPlayerRepository.managedQueueInfo.availableSongsStream.listen((_) => _setAvSongs()); + _audioPlayerRepository.managedQueueInfo.availableSongsStream + .listen((_) => _setAvSongs()); _audioPlayerRepository.shuffleModeStream.listen((_) => _setAvSongs()); _audioPlayerRepository.playableStream.listen((_) => _setAvSongs()); } @@ -79,11 +81,13 @@ abstract class _AudioStore with Store { _audioPlayerRepository.currentSongStream.asObservable(); @observable - late ObservableStream playingStream = _audioPlayerRepository.playingStream.asObservable(); + late ObservableStream playingStream = + _audioPlayerRepository.playingStream.asObservable(); @observable - late ObservableStream currentPositionStream = - _audioPlayerRepository.positionStream.asObservable(initialValue: const Duration(seconds: 0)); + late ObservableStream currentPositionStream = _audioPlayerRepository + .positionStream + .asObservable(initialValue: const Duration(seconds: 0)); @readonly late List _queue = []; @@ -131,11 +135,22 @@ abstract class _AudioStore with Store { @computed bool get hasNext => - (queueIndexStream.value != null && queueIndexStream.value! < _queue.length - 1) || + (queueIndexStream.value != null && + queueIndexStream.value! < _queue.length - 1) || (loopModeStream.value ?? LoopMode.off) != LoopMode.off; - Future playSong(int index, List songList, Playable playable) async { - _playSongs(songs: songList, initialIndex: index, playable: playable, keepInitialIndex: true); + @computed + bool get hasPrevious => + (queueIndexStream.value != null && queueIndexStream.value! > 0) || + (loopModeStream.value ?? LoopMode.off) != LoopMode.off; + + Future playSong( + int index, List songList, Playable playable) async { + _playSongs( + songs: songList, + initialIndex: index, + playable: playable, + keepInitialIndex: true); } Future play() async => _audioPlayerRepository.play(); @@ -144,9 +159,11 @@ abstract class _AudioStore with Store { Future skipToNext() async => _seekToNext(); - Future skipToPrevious() async => _audioPlayerRepository.seekToPrevious(); + Future skipToPrevious() async => + _audioPlayerRepository.seekToPrevious(); - Future seekToIndex(int index) async => _audioPlayerRepository.seekToIndex(index); + Future seekToIndex(int index) async => + _audioPlayerRepository.seekToIndex(index); Future seekToPosition(double position) async => _audioPlayerRepository.seekToPosition(position); @@ -154,15 +171,20 @@ abstract class _AudioStore with Store { Future setShuffleMode(ShuffleMode shuffleMode) async => _audioPlayerRepository.setShuffleMode(shuffleMode); - Future setLoopMode(LoopMode loopMode) async => _audioPlayerRepository.setLoopMode(loopMode); + Future setLoopMode(LoopMode loopMode) async => + _audioPlayerRepository.setLoopMode(loopMode); - Future shuffleAll(ShuffleMode shuffleMode) async => _shuffleAll(shuffleMode); + Future shuffleAll(ShuffleMode shuffleMode) async => + _shuffleAll(shuffleMode); - Future addToQueue(List songs) async => _audioPlayerRepository.addToQueue(songs); + Future addToQueue(List songs) async => + _audioPlayerRepository.addToQueue(songs); - Future playNext(List songs) async => _audioPlayerRepository.playNext(songs); + Future playNext(List songs) async => + _audioPlayerRepository.playNext(songs); - Future appendToNext(List songs) async => _audioPlayerRepository.addToNext(songs); + Future appendToNext(List songs) async => + _audioPlayerRepository.addToNext(songs); Future moveQueueItem(int oldIndex, int newIndex) async => _audioPlayerRepository.moveQueueItem(oldIndex, newIndex); @@ -172,13 +194,15 @@ abstract class _AudioStore with Store { Future playAlbum(Album album) async => _playAlbum(album); - Future playSmartList(SmartList smartList) async => _playSmartList(smartList); + Future playSmartList(SmartList smartList) async => + _playSmartList(smartList); Future playPlaylist(Playlist playlist) async => _playPlaylist(playlist); Future playArtist(Artist artist, ShuffleMode? shuffleMode) async => _playArtist(artist, shuffleMode); - Future playPlayable(Playable playable, ShuffleMode? shuffleMode) async => + Future playPlayable( + Playable playable, ShuffleMode? shuffleMode) async => _playPlayable(playable, shuffleMode); } diff --git a/src/lib/presentation/widgets/album_art_swipe.dart b/src/lib/presentation/widgets/album_art_swipe.dart new file mode 100644 index 0000000..7c90e73 --- /dev/null +++ b/src/lib/presentation/widgets/album_art_swipe.dart @@ -0,0 +1,51 @@ +import 'package:fimber/fimber.dart'; +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:mucke/presentation/widgets/album_art.dart'; + +import '../state/audio_store.dart'; + +class AlbumArtSwipe extends StatefulWidget { + const AlbumArtSwipe({Key? key, required this.queueIndex}) : super(key: key); + + final int queueIndex; + + @override + _AlbumArtSwipeState createState() => _AlbumArtSwipeState(queueIndex: queueIndex); +} + +class _AlbumArtSwipeState extends State { + _AlbumArtSwipeState({required this.queueIndex}) : super(); + static final _log = FimberLog('AlbumArtSwipe'); + + int queueIndex; + late PageController controller; + static final AudioStore audioStore = GetIt.I(); + + @override + void initState() { + super.initState(); + controller = PageController(initialPage: audioStore.queueIndexStream.value!); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + controller = PageController(initialPage: queueIndex); + return PageView.builder( + controller: controller, + itemCount: audioStore.queueLength, + itemBuilder: (_, index) { + return AlbumArt(song: audioStore.queue[index].song); + }, + onPageChanged: (value) { + audioStore.seekToIndex(value); + }, + ); + } +}