Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replaced just_audio with audioplayers & Refactored Playback provider #131

Merged
merged 10 commits into from
Jul 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"cmake.configureOnOpen": false
"cmake.configureOnOpen": false,
"cSpell.words": [
"Mpris"
]
}
19 changes: 13 additions & 6 deletions CONTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ All types of contributions are encouraged and valued. See the [Table of Contents

## Table of Contents

- [Code of Conduct](#code-of-conduct)
- [I Have a Question](#i-have-a-question)
- [I Want To Contribute](#i-want-to-contribute)
- [Reporting Bugs](#reporting-bugs)
- [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution)
- [Contributing to Spotube](#contributing-to-spotube)
- [Table of Contents](#table-of-contents)
- [Code of Conduct](#code-of-conduct)
- [I Have a Question](#i-have-a-question)
- [I Want To Contribute](#i-want-to-contribute)
- [Reporting Bugs](#reporting-bugs)
- [Before Submitting a Bug Report](#before-submitting-a-bug-report)
- [How Do I Submit a Good Bug Report?](#how-do-i-submit-a-good-bug-report)
- [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution)


## Code of Conduct
Expand Down Expand Up @@ -109,6 +113,9 @@ Enhancement suggestions are tracked as [GitHub issues](https://github.com/KRTirt

### Your First Code Contribution

<!-- Download -->
audioplayers requirement https://github.com/bluefireteam/audioplayers/blob/main/packages/audioplayers_linux/requirements.md

Do the following:
- Download the latest Flutter SDK (>=2.15.1) & enable desktop support
- Install Development dependencies in linux
Expand Down
14 changes: 6 additions & 8 deletions lib/components/Album/AlbumCard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ class AlbumCard extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
Playback playback = ref.watch(playbackProvider);
bool isPlaylistPlaying = playback.currentPlaylist != null &&
playback.currentPlaylist!.id == album.id;
bool isPlaylistPlaying =
playback.playlist != null && playback.playlist!.id == album.id;
final int marginH =
useBreakpointValue(sm: 10, md: 15, lg: 20, xl: 20, xxl: 20);
return PlaybuttonCard(
imageUrl: imageToUrlString(album.images),
margin: EdgeInsets.symmetric(horizontal: marginH.toDouble()),
isPlaying: playback.currentPlaylist?.id != null &&
playback.currentPlaylist?.id == album.id,
isPlaying:
playback.playlist?.id != null && playback.playlist?.id == album.id,
title: album.name!,
description:
"Album • ${artistsToString<ArtistSimple>(album.artists ?? [])}",
Expand All @@ -41,14 +41,12 @@ class AlbumCard extends HookConsumerWidget {
.toList();
if (tracks.isEmpty) return;

playback.setCurrentPlaylist = CurrentPlaylist(
await playback.playPlaylist(CurrentPlaylist(
tracks: tracks,
id: album.id!,
name: album.name!,
thumbnail: album.images!.first.url!,
);
playback.setCurrentTrack = tracks.first;
await playback.startPlaying();
));
},
);
}
Expand Down
28 changes: 14 additions & 14 deletions lib/components/Album/AlbumView.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/Shared/HeartButton.dart';
Expand All @@ -18,24 +17,25 @@ class AlbumView extends HookConsumerWidget {
final AlbumSimple album;
const AlbumView(this.album, {Key? key}) : super(key: key);

playPlaylist(Playback playback, List<Track> tracks,
Future<void> playPlaylist(Playback playback, List<Track> tracks,
{Track? currentTrack}) async {
currentTrack ??= tracks.first;
var isPlaylistPlaying = playback.currentPlaylist?.id == album.id;
final isPlaylistPlaying = playback.playlist?.id == album.id;
if (!isPlaylistPlaying) {
playback.setCurrentPlaylist = CurrentPlaylist(
tracks: tracks,
id: album.id!,
name: album.name!,
thumbnail: imageToUrlString(album.images),
await playback.playPlaylist(
CurrentPlaylist(
tracks: tracks,
id: album.id!,
name: album.name!,
thumbnail: imageToUrlString(album.images),
),
tracks.indexWhere((s) => s.id == currentTrack?.id),
);
playback.setCurrentTrack = currentTrack;
} else if (isPlaylistPlaying &&
currentTrack.id != null &&
currentTrack.id != playback.currentTrack?.id) {
playback.setCurrentTrack = currentTrack;
currentTrack.id != playback.track?.id) {
await playback.play(currentTrack);
}
await playback.startPlaying();
}

@override
Expand All @@ -54,8 +54,8 @@ class AlbumView extends HookConsumerWidget {

return TrackCollectionView(
id: album.id!,
isPlaying: playback.currentPlaylist?.id != null &&
playback.currentPlaylist?.id == album.id,
isPlaying:
playback.playlist?.id != null && playback.playlist?.id == album.id,
title: album.name!,
titleImage: albumArt,
tracksSnapshot: tracksSnapshot,
Expand Down
21 changes: 11 additions & 10 deletions lib/components/Artist/ArtistProfile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,24 +183,25 @@ class ArtistProfile extends HookConsumerWidget {
topTracksSnapshot.when(
data: (topTracks) {
final isPlaylistPlaying =
playback.currentPlaylist?.id == data.id;
playback.playlist?.id == data.id;
playPlaylist(List<Track> tracks,
{Track? currentTrack}) async {
currentTrack ??= tracks.first;
if (!isPlaylistPlaying) {
playback.setCurrentPlaylist = CurrentPlaylist(
tracks: tracks,
id: data.id!,
name: "${data.name!} To Tracks",
thumbnail: imageToUrlString(data.images),
await playback.playPlaylist(
CurrentPlaylist(
tracks: tracks,
id: data.id!,
name: "${data.name!} To Tracks",
thumbnail: imageToUrlString(data.images),
),
tracks.indexWhere((s) => s.id == currentTrack?.id),
);
playback.setCurrentTrack = currentTrack;
} else if (isPlaylistPlaying &&
currentTrack.id != null &&
currentTrack.id != playback.currentTrack?.id) {
playback.setCurrentTrack = currentTrack;
currentTrack.id != playback.track?.id) {
await playback.play(currentTrack);
}
await playback.startPlaying();
}

return Column(children: [
Expand Down
8 changes: 4 additions & 4 deletions lib/components/Lyrics/Lyrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ class Lyrics extends HookConsumerWidget {
children: [
Center(
child: Text(
playback.currentTrack?.name ?? "",
playback.track?.name ?? "",
style: breakpoint >= Breakpoints.md
? textTheme.headline3
: textTheme.headline4?.copyWith(fontSize: 25),
),
),
Center(
child: Text(
artistsToString<Artist>(playback.currentTrack?.artists ?? []),
artistsToString<Artist>(playback.track?.artists ?? []),
style: breakpoint >= Breakpoints.md
? textTheme.headline5
: textTheme.headline6,
Expand All @@ -45,15 +45,15 @@ class Lyrics extends HookConsumerWidget {
child: geniusLyricsSnapshot.when(
data: (lyrics) {
return Text(
lyrics == null && playback.currentTrack == null
lyrics == null && playback.track == null
? "No Track being played currently"
: lyrics!,
style: textTheme.headline6
?.copyWith(color: textTheme.headline1?.color),
);
},
error: (error, __) => Text(
"Sorry, no Lyrics were found for `${playback.currentTrack?.name}` :'("),
"Sorry, no Lyrics were found for `${playback.track?.name}` :'("),
loading: () => const ShimmerLyrics(),
),
),
Expand Down
14 changes: 7 additions & 7 deletions lib/components/Lyrics/SyncedLyrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class SyncedLyrics extends HookConsumerWidget {
controller.scrollToIndex(0);
failed.value = false;
return null;
}, [playback.currentTrack]);
}, [playback.track]);

useEffect(() {
if (lyricValue != null && lyricValue.rating <= 2) {
Expand Down Expand Up @@ -99,20 +99,20 @@ class SyncedLyrics extends HookConsumerWidget {
Center(
child: SizedBox(
height: breakpoint >= Breakpoints.md ? 50 : 30,
child: playback.currentTrack?.name != null &&
playback.currentTrack!.name!.length > 29
child: playback.track?.name != null &&
playback.track!.name!.length > 29
? SpotubeMarqueeText(
text: playback.currentTrack?.name ?? "Not Playing",
text: playback.track?.name ?? "Not Playing",
style: headlineTextStyle,
)
: Text(
playback.currentTrack?.name ?? "Not Playing",
playback.track?.name ?? "Not Playing",
style: headlineTextStyle,
),
)),
Center(
child: Text(
artistsToString<Artist>(playback.currentTrack?.artists ?? []),
artistsToString<Artist>(playback.track?.artists ?? []),
style: breakpoint >= Breakpoints.md
? textTheme.headline5
: textTheme.headline6,
Expand Down Expand Up @@ -157,7 +157,7 @@ class SyncedLyrics extends HookConsumerWidget {
},
),
),
if (playback.currentTrack != null &&
if (playback.track != null &&
(lyricValue == null || lyricValue.lyrics.isEmpty == true))
const Expanded(child: ShimmerLyrics()),
],
Expand Down
81 changes: 28 additions & 53 deletions lib/components/Player/Player.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import 'dart:async';

import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/components/Player/PlayerActions.dart';
import 'package:spotube/components/Player/PlayerOverlay.dart';
import 'package:spotube/components/Player/PlayerTrackDetails.dart';
import 'package:spotube/components/Player/PlayerControls.dart';
import 'package:spotube/helpers/image-to-url-string.dart';
import 'package:spotube/hooks/useBreakpoints.dart';
import 'package:spotube/models/LocalStorageKeys.dart';
import 'package:spotube/models/Logger.dart';
import 'package:spotube/provider/Playback.dart';
import 'package:flutter/material.dart';
import 'package:spotube/utils/AudioPlayerHandler.dart';

class Player extends HookConsumerWidget {
Player({Key? key}) : super(key: key);
Expand All @@ -23,41 +18,14 @@ class Player extends HookConsumerWidget {
Widget build(BuildContext context, ref) {
Playback playback = ref.watch(playbackProvider);

final _volume = useState(0.0);

final breakpoint = useBreakpoints();

final AudioPlayerHandler player = playback.player;

final Future<SharedPreferences> future =
useMemoized(SharedPreferences.getInstance);
final AsyncSnapshot<SharedPreferences?> localStorage =
useFuture(future, initialData: null);

useEffect(() {
/// warm up the audio player before playing actual audio
/// It's for resolving unresolved issue related to just_audio's
/// [disposeAllPlayers] method which is throwing
/// [UnimplementedException] in the [PlatformInterface]
/// implementation
player.core.setAsset("assets/warmer.mp3");
return null;
}, []);

useEffect(() {
if (localStorage.hasData) {
_volume.value = localStorage.data?.getDouble(LocalStorageKeys.volume) ??
player.core.volume;
}
return null;
}, [localStorage.data]);

String albumArt = useMemoized(
() => imageToUrlString(
playback.currentTrack?.album?.images,
index: (playback.currentTrack?.album?.images?.length ?? 1) - 1,
playback.track?.album?.images,
index: (playback.track?.album?.images?.length ?? 1) - 1,
),
[playback.currentTrack?.album?.images],
[playback.track?.album?.images],
);

final entryRef = useRef<OverlayEntry?>(null);
Expand All @@ -82,7 +50,7 @@ class Player extends HookConsumerWidget {
// entry will result in splashing while resizing the window
if (breakpoint.isLessThanOrEqualTo(Breakpoints.md) &&
entryRef.value == null &&
playback.currentTrack != null) {
playback.track != null) {
entryRef.value = OverlayEntry(
opaque: false,
builder: (context) => PlayerOverlay(albumArt: albumArt),
Expand All @@ -104,7 +72,7 @@ class Player extends HookConsumerWidget {
return () {
disposeOverlay();
};
}, [breakpoint, playback.currentTrack]);
}, [breakpoint, playback.track]);

// returning an empty non spacious Container as the overlay will take
// place in the global overlay stack aka [_entries]
Expand Down Expand Up @@ -135,22 +103,29 @@ class Player extends HookConsumerWidget {
Container(
height: 20,
constraints: const BoxConstraints(maxWidth: 200),
child: Slider.adaptive(
value: _volume.value,
onChanged: (value) async {
try {
await player.core.setVolume(value).then((_) {
_volume.value = value;
localStorage.data?.setDouble(
LocalStorageKeys.volume,
value,
);
});
} catch (e, stack) {
logger.e("onChange", e, stack);
}
},
),
child: HookBuilder(builder: (context) {
final volume = useState(
useMemoized(() => playback.volume, []),
);
return Slider.adaptive(
min: 0,
max: 1,
value: volume.value,
onChanged: (v) {
volume.value = v;
},
onChangeEnd: (value) async {
try {
// You don't really need to know why but this
// way it works only
await playback.setVolume(value);
await playback.setVolume(value);
} catch (e, stack) {
logger.e("onChange", e, stack);
}
},
);
}),
),
PlayerActions()
],
Expand Down
Loading