Make it possible to switch songs by swiping in the currently playing view (#39)
* Add swipe for switching songs * Wip background scroll widget * add album background list * this looks better. I still need to figure out why the wrong picture is shown and how to have the picture move in from the right direction * use correct picture for album art * Remove unnecessary scaffold * remove commented code * Implement AlbumArt Swiping with PageView Co-authored-by: Frieder Hannenheim <frieder12.fml@pm.me>
This commit is contained in:
parent
b02bf80649
commit
37e7a03255
3 changed files with 99 additions and 22 deletions
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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<bool> playingStream = _audioPlayerRepository.playingStream.asObservable();
|
||||
late ObservableStream<bool> playingStream =
|
||||
_audioPlayerRepository.playingStream.asObservable();
|
||||
|
||||
@observable
|
||||
late ObservableStream<Duration> currentPositionStream =
|
||||
_audioPlayerRepository.positionStream.asObservable(initialValue: const Duration(seconds: 0));
|
||||
late ObservableStream<Duration> currentPositionStream = _audioPlayerRepository
|
||||
.positionStream
|
||||
.asObservable(initialValue: const Duration(seconds: 0));
|
||||
|
||||
@readonly
|
||||
late List<QueueItem> _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<void> playSong(int index, List<Song> 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<void> playSong(
|
||||
int index, List<Song> songList, Playable playable) async {
|
||||
_playSongs(
|
||||
songs: songList,
|
||||
initialIndex: index,
|
||||
playable: playable,
|
||||
keepInitialIndex: true);
|
||||
}
|
||||
|
||||
Future<void> play() async => _audioPlayerRepository.play();
|
||||
|
@ -144,9 +159,11 @@ abstract class _AudioStore with Store {
|
|||
|
||||
Future<void> skipToNext() async => _seekToNext();
|
||||
|
||||
Future<void> skipToPrevious() async => _audioPlayerRepository.seekToPrevious();
|
||||
Future<void> skipToPrevious() async =>
|
||||
_audioPlayerRepository.seekToPrevious();
|
||||
|
||||
Future<void> seekToIndex(int index) async => _audioPlayerRepository.seekToIndex(index);
|
||||
Future<void> seekToIndex(int index) async =>
|
||||
_audioPlayerRepository.seekToIndex(index);
|
||||
|
||||
Future<void> seekToPosition(double position) async =>
|
||||
_audioPlayerRepository.seekToPosition(position);
|
||||
|
@ -154,15 +171,20 @@ abstract class _AudioStore with Store {
|
|||
Future<void> setShuffleMode(ShuffleMode shuffleMode) async =>
|
||||
_audioPlayerRepository.setShuffleMode(shuffleMode);
|
||||
|
||||
Future<void> setLoopMode(LoopMode loopMode) async => _audioPlayerRepository.setLoopMode(loopMode);
|
||||
Future<void> setLoopMode(LoopMode loopMode) async =>
|
||||
_audioPlayerRepository.setLoopMode(loopMode);
|
||||
|
||||
Future<void> shuffleAll(ShuffleMode shuffleMode) async => _shuffleAll(shuffleMode);
|
||||
Future<void> shuffleAll(ShuffleMode shuffleMode) async =>
|
||||
_shuffleAll(shuffleMode);
|
||||
|
||||
Future<void> addToQueue(List<Song> songs) async => _audioPlayerRepository.addToQueue(songs);
|
||||
Future<void> addToQueue(List<Song> songs) async =>
|
||||
_audioPlayerRepository.addToQueue(songs);
|
||||
|
||||
Future<void> playNext(List<Song> songs) async => _audioPlayerRepository.playNext(songs);
|
||||
Future<void> playNext(List<Song> songs) async =>
|
||||
_audioPlayerRepository.playNext(songs);
|
||||
|
||||
Future<void> appendToNext(List<Song> songs) async => _audioPlayerRepository.addToNext(songs);
|
||||
Future<void> appendToNext(List<Song> songs) async =>
|
||||
_audioPlayerRepository.addToNext(songs);
|
||||
|
||||
Future<void> moveQueueItem(int oldIndex, int newIndex) async =>
|
||||
_audioPlayerRepository.moveQueueItem(oldIndex, newIndex);
|
||||
|
@ -172,13 +194,15 @@ abstract class _AudioStore with Store {
|
|||
|
||||
Future<void> playAlbum(Album album) async => _playAlbum(album);
|
||||
|
||||
Future<void> playSmartList(SmartList smartList) async => _playSmartList(smartList);
|
||||
Future<void> playSmartList(SmartList smartList) async =>
|
||||
_playSmartList(smartList);
|
||||
|
||||
Future<void> playPlaylist(Playlist playlist) async => _playPlaylist(playlist);
|
||||
|
||||
Future<void> playArtist(Artist artist, ShuffleMode? shuffleMode) async =>
|
||||
_playArtist(artist, shuffleMode);
|
||||
|
||||
Future<void> playPlayable(Playable playable, ShuffleMode? shuffleMode) async =>
|
||||
Future<void> playPlayable(
|
||||
Playable playable, ShuffleMode? shuffleMode) async =>
|
||||
_playPlayable(playable, shuffleMode);
|
||||
}
|
||||
|
|
51
src/lib/presentation/widgets/album_art_swipe.dart
Normal file
51
src/lib/presentation/widgets/album_art_swipe.dart
Normal file
|
@ -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<AlbumArtSwipe> {
|
||||
_AlbumArtSwipeState({required this.queueIndex}) : super();
|
||||
static final _log = FimberLog('AlbumArtSwipe');
|
||||
|
||||
int queueIndex;
|
||||
late PageController controller;
|
||||
static final AudioStore audioStore = GetIt.I<AudioStore>();
|
||||
|
||||
@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);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue