implemented play/pause
This commit is contained in:
parent
7fbd4a07a2
commit
eff0dc29a6
18 changed files with 289 additions and 59 deletions
6
lib/domain/entities/playback_state.dart
Normal file
6
lib/domain/entities/playback_state.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
enum PlaybackState {
|
||||
none,
|
||||
playing,
|
||||
paused,
|
||||
stopped,
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
import 'package:dartz/dartz.dart';
|
||||
|
||||
import '../../core/error/failures.dart';
|
||||
import '../entities/playback_state.dart';
|
||||
import '../entities/song.dart';
|
||||
|
||||
abstract class AudioRepository {
|
||||
Stream<Song> get watchCurrentSong;
|
||||
Stream<Song> get currentSongStream;
|
||||
Stream<PlaybackState> get playbackStateStream;
|
||||
|
||||
Future<Either<Failure, void>> playSong(int index, List<Song> songList);
|
||||
Future<Either<Failure, void>> play();
|
||||
Future<Either<Failure, void>> pause();
|
||||
}
|
|
@ -50,7 +50,7 @@ class _RootPageState extends State<RootPage> {
|
|||
var navIndex = 1;
|
||||
|
||||
final List<Widget> _pages = <Widget>[
|
||||
HomePage(),
|
||||
const HomePage(),
|
||||
const LibraryPage(
|
||||
key: PageStorageKey('LibraryPage'),
|
||||
),
|
||||
|
@ -62,8 +62,7 @@ class _RootPageState extends State<RootPage> {
|
|||
@override
|
||||
void didChangeDependencies() {
|
||||
final MusicDataStore _musicStore = Provider.of<MusicDataStore>(context);
|
||||
_musicStore.fetchAlbums();
|
||||
_musicStore.fetchSongs();
|
||||
_musicStore.init();
|
||||
|
||||
final AudioStore _audioStore = Provider.of<AudioStore>(context);
|
||||
_audioStore.init();
|
||||
|
@ -80,6 +79,7 @@ class _RootPageState extends State<RootPage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print('RootPage.build');
|
||||
return Scaffold(
|
||||
body: IndexedStack(
|
||||
index: navIndex,
|
||||
|
|
|
@ -6,6 +6,7 @@ import '../../domain/entities/song.dart';
|
|||
import '../state/audio_store.dart';
|
||||
import '../theming.dart';
|
||||
import '../widgets/album_art.dart';
|
||||
import '../widgets/play_pause_button.dart';
|
||||
import '../widgets/queue_card.dart';
|
||||
import '../widgets/time_progress_indicator.dart';
|
||||
|
||||
|
@ -99,9 +100,9 @@ class CurrentlyPlayingPage extends StatelessWidget {
|
|||
children: [
|
||||
Icon(Icons.repeat, size: 20.0),
|
||||
Icon(Icons.skip_previous, size: 32.0),
|
||||
Icon(
|
||||
Icons.play_circle_filled,
|
||||
size: 52.0,
|
||||
const PlayPauseButton(
|
||||
circle: true,
|
||||
iconSize: 52.0,
|
||||
),
|
||||
Icon(Icons.skip_next, size: 32.0),
|
||||
Icon(Icons.shuffle, size: 20.0),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
HomePage({Key key}) : super(key: key);
|
||||
const HomePage({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_HomePageState createState() => _HomePageState();
|
||||
|
@ -10,8 +10,11 @@ class HomePage extends StatefulWidget {
|
|||
class _HomePageState extends State<HomePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print('HomePage.build');
|
||||
return Container(
|
||||
child: Center(child: Text("Home Page"),),
|
||||
child: const Center(
|
||||
child: Text('Home Page'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:meta/meta.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
import '../../domain/entities/playback_state.dart';
|
||||
import '../../domain/entities/song.dart';
|
||||
import '../../domain/repositories/audio_repository.dart';
|
||||
import '../../domain/repositories/music_data_repository.dart';
|
||||
|
@ -8,7 +9,9 @@ import '../../domain/repositories/music_data_repository.dart';
|
|||
part 'audio_store.g.dart';
|
||||
|
||||
class AudioStore extends _AudioStore with _$AudioStore {
|
||||
AudioStore({@required MusicDataRepository musicDataRepository, @required AudioRepository audioRepository})
|
||||
AudioStore(
|
||||
{@required MusicDataRepository musicDataRepository,
|
||||
@required AudioRepository audioRepository})
|
||||
: super(musicDataRepository, audioRepository);
|
||||
}
|
||||
|
||||
|
@ -18,25 +21,36 @@ abstract class _AudioStore with Store {
|
|||
final MusicDataRepository _musicDataRepository;
|
||||
final AudioRepository _audioRepository;
|
||||
|
||||
ReactionDisposer _disposer;
|
||||
bool _initialized = false;
|
||||
final List<ReactionDisposer> _disposers = [];
|
||||
|
||||
@observable
|
||||
ObservableStream<Song> currentSong;
|
||||
|
||||
@observable
|
||||
Song song;
|
||||
|
||||
@observable
|
||||
ObservableStream<PlaybackState> playbackStateStream;
|
||||
|
||||
@action
|
||||
Future<void> init() async {
|
||||
currentSong = _audioRepository.watchCurrentSong.asObservable();
|
||||
if (!_initialized) {
|
||||
print('AudioStore.init');
|
||||
currentSong = _audioRepository.currentSongStream.asObservable();
|
||||
|
||||
_disposer = autorun((_) {
|
||||
updateSong(currentSong.value);
|
||||
});
|
||||
_disposers.add(autorun((_) {
|
||||
updateSong(currentSong.value);
|
||||
}));
|
||||
|
||||
playbackStateStream = _audioRepository.playbackStateStream.asObservable();
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_disposer();
|
||||
print('AudioStore.dispose');
|
||||
_disposers.forEach((d) => d());
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -44,6 +58,16 @@ abstract class _AudioStore with Store {
|
|||
_audioRepository.playSong(index, songList);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> play() async {
|
||||
_audioRepository.play();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> pause() async {
|
||||
_audioRepository.pause();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> updateSong(Song streamValue) async {
|
||||
print('updateSong');
|
||||
|
@ -52,5 +76,4 @@ abstract class _AudioStore with Store {
|
|||
song = streamValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,26 @@ mixin _$AudioStore on _AudioStore, Store {
|
|||
}, _$songAtom, name: '${_$songAtom.name}_set');
|
||||
}
|
||||
|
||||
final _$playbackStateStreamAtom =
|
||||
Atom(name: '_AudioStore.playbackStateStream');
|
||||
|
||||
@override
|
||||
ObservableStream<PlaybackState> get playbackStateStream {
|
||||
_$playbackStateStreamAtom.context
|
||||
.enforceReadPolicy(_$playbackStateStreamAtom);
|
||||
_$playbackStateStreamAtom.reportObserved();
|
||||
return super.playbackStateStream;
|
||||
}
|
||||
|
||||
@override
|
||||
set playbackStateStream(ObservableStream<PlaybackState> value) {
|
||||
_$playbackStateStreamAtom.context.conditionallyRunInAction(() {
|
||||
super.playbackStateStream = value;
|
||||
_$playbackStateStreamAtom.reportChanged();
|
||||
}, _$playbackStateStreamAtom,
|
||||
name: '${_$playbackStateStreamAtom.name}_set');
|
||||
}
|
||||
|
||||
final _$initAsyncAction = AsyncAction('init');
|
||||
|
||||
@override
|
||||
|
@ -57,6 +77,20 @@ mixin _$AudioStore on _AudioStore, Store {
|
|||
return _$playSongAsyncAction.run(() => super.playSong(index, songList));
|
||||
}
|
||||
|
||||
final _$playAsyncAction = AsyncAction('play');
|
||||
|
||||
@override
|
||||
Future<void> play() {
|
||||
return _$playAsyncAction.run(() => super.play());
|
||||
}
|
||||
|
||||
final _$pauseAsyncAction = AsyncAction('pause');
|
||||
|
||||
@override
|
||||
Future<void> pause() {
|
||||
return _$pauseAsyncAction.run(() => super.pause());
|
||||
}
|
||||
|
||||
final _$updateSongAsyncAction = AsyncAction('updateSong');
|
||||
|
||||
@override
|
||||
|
@ -67,7 +101,7 @@ mixin _$AudioStore on _AudioStore, Store {
|
|||
@override
|
||||
String toString() {
|
||||
final string =
|
||||
'currentSong: ${currentSong.toString()},song: ${song.toString()}';
|
||||
'currentSong: ${currentSong.toString()},song: ${song.toString()},playbackStateStream: ${playbackStateStream.toString()}';
|
||||
return '{$string}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ abstract class _MusicDataStore with Store {
|
|||
_getAlbums = GetAlbums(_musicDataRepository),
|
||||
_getSongs = GetSongs(_musicDataRepository);
|
||||
|
||||
bool _initialized = false;
|
||||
|
||||
final UpdateDatabase _updateDatabase;
|
||||
final GetAlbums _getAlbums;
|
||||
final GetSongs _getSongs;
|
||||
|
@ -39,6 +41,17 @@ abstract class _MusicDataStore with Store {
|
|||
@observable
|
||||
bool isUpdatingDatabase = false;
|
||||
|
||||
@action
|
||||
Future<void> init() async {
|
||||
if (!_initialized) {
|
||||
print('MusicDataStore.init');
|
||||
fetchAlbums();
|
||||
fetchSongs();
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> updateDatabase() async {
|
||||
isUpdatingDatabase = true;
|
||||
|
|
|
@ -79,6 +79,13 @@ mixin _$MusicDataStore on _MusicDataStore, Store {
|
|||
}, _$isUpdatingDatabaseAtom, name: '${_$isUpdatingDatabaseAtom.name}_set');
|
||||
}
|
||||
|
||||
final _$initAsyncAction = AsyncAction('init');
|
||||
|
||||
@override
|
||||
Future<void> init() {
|
||||
return _$initAsyncAction.run(() => super.init());
|
||||
}
|
||||
|
||||
final _$updateDatabaseAsyncAction = AsyncAction('updateDatabase');
|
||||
|
||||
@override
|
||||
|
|
|
@ -16,10 +16,14 @@ class AlbumArt extends StatelessWidget {
|
|||
elevation: 2.0,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
margin: const EdgeInsets.all(0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(2.0),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Image(
|
||||
image: getAlbumImage(song.albumArtPath),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
|
|
|
@ -6,6 +6,7 @@ import '../../domain/entities/song.dart';
|
|||
import '../pages/currently_playing.dart';
|
||||
import '../state/audio_store.dart';
|
||||
import '../utils.dart';
|
||||
import 'play_pause_button.dart';
|
||||
|
||||
class CurrentlyPlayingBar extends StatelessWidget {
|
||||
const CurrentlyPlayingBar({Key key}) : super(key: key);
|
||||
|
@ -52,18 +53,17 @@ class CurrentlyPlayingBar extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
icon: Icon(Icons.favorite_border),
|
||||
onPressed: () {},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.pause),
|
||||
onPressed: () {},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.skip_next),
|
||||
onPressed: () {},
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.favorite_border),
|
||||
// onPressed: () {},
|
||||
// ),
|
||||
const PlayPauseButton(
|
||||
circle: false,
|
||||
),
|
||||
// IconButton(
|
||||
// icon: Icon(Icons.skip_next),
|
||||
// onPressed: () {},
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_audio_query/flutter_audio_query.dart';
|
||||
import 'package:mosh/domain/repositories/audio_repository.dart';
|
||||
import 'package:mosh/domain/repositories/music_data_repository.dart';
|
||||
import 'package:mosh/presentation/state/audio_store.dart';
|
||||
import 'package:mosh/presentation/state/music_data_store.dart';
|
||||
import 'package:mosh/system/datasources/audio_manager.dart';
|
||||
import 'package:mosh/system/datasources/local_music_fetcher.dart';
|
||||
import 'package:mosh/system/datasources/moor_music_data_source.dart';
|
||||
import 'package:mosh/system/repositories/audio_repository_impl.dart';
|
||||
import 'package:mosh/system/repositories/music_data_repository_impl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../domain/repositories/audio_repository.dart';
|
||||
import '../../domain/repositories/music_data_repository.dart';
|
||||
import '../../system/datasources/audio_manager.dart';
|
||||
import '../../system/datasources/local_music_fetcher.dart';
|
||||
import '../../system/datasources/moor_music_data_source.dart';
|
||||
import '../../system/repositories/audio_repository_impl.dart';
|
||||
import '../../system/repositories/music_data_repository_impl.dart';
|
||||
import '../state/audio_store.dart';
|
||||
import '../state/music_data_store.dart';
|
||||
|
||||
class InjectionWidget extends StatelessWidget {
|
||||
const InjectionWidget({Key key, this.child}) : super(key: key);
|
||||
|
||||
|
@ -18,6 +19,7 @@ class InjectionWidget extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print('InjectionWidget.build');
|
||||
// TODO: this does not dispose correctly! use ProxyProvider
|
||||
|
||||
final MusicDataRepository musicDataRepository = MusicDataRepositoryImpl(
|
||||
|
|
43
lib/presentation/widgets/play_pause_button.dart
Normal file
43
lib/presentation/widgets/play_pause_button.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../domain/entities/playback_state.dart';
|
||||
import '../state/audio_store.dart';
|
||||
|
||||
class PlayPauseButton extends StatelessWidget {
|
||||
const PlayPauseButton({Key key, this.circle = false, this.iconSize = 24.0}) : super(key: key);
|
||||
|
||||
final bool circle;
|
||||
final double iconSize;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AudioStore audioStore = Provider.of<AudioStore>(context);
|
||||
|
||||
return Observer(
|
||||
builder: (BuildContext context) {
|
||||
switch (audioStore.playbackStateStream.value) {
|
||||
case PlaybackState.playing:
|
||||
return IconButton(
|
||||
icon: circle ? Icon(Icons.pause_circle_filled) : Icon(Icons.pause),
|
||||
iconSize: iconSize,
|
||||
onPressed: () {
|
||||
audioStore.pause();
|
||||
},
|
||||
);
|
||||
case PlaybackState.paused:
|
||||
return IconButton(
|
||||
icon: circle ? Icon(Icons.play_circle_filled) : Icon(Icons.play_arrow),
|
||||
iconSize: iconSize,
|
||||
onPressed: () {
|
||||
audioStore.play();
|
||||
},
|
||||
);
|
||||
default:
|
||||
return Container(height: 0, width: 0,);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,16 +3,31 @@ import 'dart:async';
|
|||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:just_audio/just_audio.dart';
|
||||
|
||||
import '../../domain/entities/playback_state.dart' as entity;
|
||||
import '../models/playback_state_model.dart';
|
||||
import '../models/song_model.dart';
|
||||
import 'audio_manager_contract.dart';
|
||||
|
||||
typedef Conversion<S, T> = T Function(S);
|
||||
|
||||
class AudioManagerImpl implements AudioManager {
|
||||
final Stream<MediaItem> _currentMediaItemStream =
|
||||
AudioService.currentMediaItemStream;
|
||||
final Stream<PlaybackState> _sourcePlaybackStateStream =
|
||||
AudioService.playbackStateStream;
|
||||
|
||||
@override
|
||||
Stream<SongModel> watchCurrentSong = AudioService.currentMediaItemStream.map(
|
||||
(currentMediaItem) {
|
||||
return SongModel.fromMediaItem(currentMediaItem);
|
||||
},
|
||||
);
|
||||
Stream<SongModel> get currentSongStream =>
|
||||
_filterStream<MediaItem, SongModel>(
|
||||
_currentMediaItemStream,
|
||||
(MediaItem mi) => SongModel.fromMediaItem(mi),
|
||||
);
|
||||
|
||||
@override
|
||||
Stream<entity.PlaybackState> get playbackStateStream => _filterStream(
|
||||
_sourcePlaybackStateStream,
|
||||
(PlaybackState ps) => PlaybackStateModel.fromASPlaybackState(ps),
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> playSong(int index, List<SongModel> songList) async {
|
||||
|
@ -23,6 +38,16 @@ class AudioManagerImpl implements AudioManager {
|
|||
AudioService.playFromMediaId(queue[index].id);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> play() async {
|
||||
await AudioService.play();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> pause() async {
|
||||
await AudioService.pause();
|
||||
}
|
||||
|
||||
Future<void> _startAudioService() async {
|
||||
if (!await AudioService.running) {
|
||||
await AudioService.start(
|
||||
|
@ -31,6 +56,18 @@ class AudioManagerImpl implements AudioManager {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
Stream<T> _filterStream<S, T>(Stream<S> stream, Conversion<S, T> fn) async* {
|
||||
T lastItem;
|
||||
|
||||
await for (final S item in stream) {
|
||||
final T newItem = fn(item);
|
||||
if (newItem != lastItem) {
|
||||
lastItem = newItem;
|
||||
yield newItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _backgroundTaskEntrypoint() {
|
||||
|
@ -45,6 +82,10 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||
|
||||
@override
|
||||
Future<void> onStart() async {
|
||||
// AudioServiceBackground.setState(
|
||||
// controls: [],
|
||||
// basicState: BasicPlaybackState.none,
|
||||
// );
|
||||
await _completer.future;
|
||||
}
|
||||
|
||||
|
@ -66,10 +107,8 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||
basicState: BasicPlaybackState.playing,
|
||||
);
|
||||
|
||||
Future.wait([
|
||||
AudioServiceBackground.setMediaItem(_mediaItems[mediaId]),
|
||||
_audioPlayer.setFilePath(mediaId),
|
||||
]);
|
||||
await AudioServiceBackground.setMediaItem(_mediaItems[mediaId]);
|
||||
await _audioPlayer.setFilePath(mediaId);
|
||||
|
||||
_audioPlayer.play();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import '../../domain/entities/playback_state.dart';
|
||||
import '../models/song_model.dart';
|
||||
|
||||
abstract class AudioManager {
|
||||
Stream<SongModel> get watchCurrentSong;
|
||||
Stream<SongModel> get currentSongStream;
|
||||
Stream<PlaybackState> get playbackStateStream;
|
||||
|
||||
Future<void> playSong(int index, List<SongModel> songList);
|
||||
Future<void> play();
|
||||
Future<void> pause();
|
||||
}
|
26
lib/system/models/playback_state_model.dart
Normal file
26
lib/system/models/playback_state_model.dart
Normal file
|
@ -0,0 +1,26 @@
|
|||
import 'package:audio_service/audio_service.dart';
|
||||
|
||||
import '../../domain/entities/playback_state.dart' as entity;
|
||||
|
||||
class PlaybackStateModel {
|
||||
|
||||
static entity.PlaybackState fromASPlaybackState(PlaybackState playbackState) {
|
||||
if (playbackState == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (playbackState.basicState) {
|
||||
case BasicPlaybackState.none:
|
||||
return entity.PlaybackState.none;
|
||||
case BasicPlaybackState.stopped:
|
||||
return entity.PlaybackState.stopped;
|
||||
case BasicPlaybackState.paused:
|
||||
return entity.PlaybackState.paused;
|
||||
case BasicPlaybackState.playing:
|
||||
return entity.PlaybackState.playing;
|
||||
default:
|
||||
return entity.PlaybackState.none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -48,15 +48,19 @@ class SongModel extends Song {
|
|||
|
||||
// TODO: test
|
||||
factory SongModel.fromMediaItem(MediaItem mediaItem) {
|
||||
final String artUri = mediaItem.artUri.replaceFirst('file://', '');
|
||||
if (mediaItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String artUri = mediaItem.artUri?.replaceFirst('file://', '');
|
||||
|
||||
return SongModel(
|
||||
title: mediaItem.title,
|
||||
album: mediaItem.album,
|
||||
artist: mediaItem.artist,
|
||||
path: mediaItem.id,
|
||||
albumArtPath: artUri,
|
||||
);
|
||||
title: mediaItem.title,
|
||||
album: mediaItem.album,
|
||||
artist: mediaItem.artist,
|
||||
path: mediaItem.id,
|
||||
albumArtPath: artUri,
|
||||
);
|
||||
}
|
||||
|
||||
final int id;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:dartz/dartz.dart';
|
||||
|
||||
import '../../core/error/failures.dart';
|
||||
import '../../domain/entities/playback_state.dart';
|
||||
import '../../domain/entities/song.dart';
|
||||
import '../../domain/repositories/audio_repository.dart';
|
||||
import '../datasources/audio_manager_contract.dart';
|
||||
|
@ -12,7 +13,11 @@ class AudioRepositoryImpl implements AudioRepository {
|
|||
final AudioManager _audioManager;
|
||||
|
||||
@override
|
||||
Stream<Song> get watchCurrentSong => _audioManager.watchCurrentSong;
|
||||
Stream<Song> get currentSongStream => _audioManager.currentSongStream;
|
||||
|
||||
@override
|
||||
Stream<PlaybackState> get playbackStateStream =>
|
||||
_audioManager.playbackStateStream;
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> playSong(int index, List<Song> songList) async {
|
||||
|
@ -25,4 +30,16 @@ class AudioRepositoryImpl implements AudioRepository {
|
|||
}
|
||||
return Left(IndexFailure());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> play() async {
|
||||
await _audioManager.play();
|
||||
return Right(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> pause() async {
|
||||
await _audioManager.pause();
|
||||
return Right(null);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue