Skip to content

Commit

Permalink
Last played playlist and song saved to hive.
Browse files Browse the repository at this point in the history
Shuffle mode and loop mode preferences saved to hive.
Bug fixes and improvements.
  • Loading branch information
ShokhrukhbekYuldoshev committed May 22, 2024
1 parent 1634386 commit b1247d9
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 15 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ Meloplay is a local music player app that plays music from your device built wit
| [get_it](https://pub.dev/packages/get_it) | 7.7.0 | Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App |
| [hive](https://pub.dev/packages/hive) | 2.2.3 | A lightweight and blazing fast key-value database |
| [hive_flutter](https://pub.dev/packages/hive_flutter) | 1.1.0 | Hive database implementation for Flutter |
| [just_audio](https://pub.dev/packages/just_audio) | 0.9.37 | A feature-rich audio player for Flutter |
| [just_audio](https://pub.dev/packages/just_audio) | 0.9.38 | A feature-rich audio player for Flutter |
| [just_audio_background](https://pub.dev/packages/just_audio_background) | 0.0.1-beta.11 | A plugin for playing audio in the background on Android and iOS. |
| [lottie](https://pub.dev/packages/lottie) | 3.1.0 | Lottie is a mobile library for Android and iOS that parses Lottie and JSON-based animations and renders them natively on mobile. |
| [lottie](https://pub.dev/packages/lottie) | 3.1.2 | Lottie is a mobile library for Android and iOS that parses Lottie and JSON-based animations and renders them natively on mobile. |
| [marquee](https://pub.dev/packages/marquee) | 2.2.3 | A Flutter widget that scrolls text infinitely. |
| [on_audio_query](https://pub.dev/packages/on_audio_query) | 2.9.0 | A Flutter plugin to query songs on Android and iOS |
| [package_info_plus](https://pub.dev/packages/package_info_plus) | 8.0.0 | Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. |
Expand Down
Binary file modified assets/images/earphones.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 69 additions & 3 deletions lib/src/data/repositories/player_repository.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'dart:io';

import 'package:hive/hive.dart';
import 'package:just_audio/just_audio.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:meloplay/src/data/repositories/song_repository.dart';
import 'package:meloplay/src/data/services/hive_box.dart';
import 'package:on_audio_query/on_audio_query.dart';

abstract class MusicPlayer {
Expand All @@ -13,6 +15,9 @@ abstract class MusicPlayer {
);
MediaItem getMediaItemFromSong(SongModel song);
SongModel getSongModelFromMediaItem(MediaItem mediaItem);
Future<void> savePlaylist();
Future<List<SongModel>> loadPlaylist();

Future<void> play();
Future<void> pause();
Future<void> stop();
Expand All @@ -33,12 +38,19 @@ abstract class MusicPlayer {
Future<void> setSpeed(double speed);
Future<void> setShuffleModeEnabled(bool enabled);
Future<void> setLoopMode(LoopMode loopMode);

Future<void> getSequenceFromPlaylist(
List<SongModel> playlist,
SongModel lastPlayedSong,
);
}

class JustAudioPlayer implements MusicPlayer {
final AudioPlayer _player = AudioPlayer();
List<SongModel> currentPlaylist = [];

var box = Hive.box(HiveBox.boxName);

@override
Future<void> init() async {
await JustAudioBackground.init(
Expand All @@ -55,13 +67,26 @@ class JustAudioPlayer implements MusicPlayer {
SongRepository().addToRecentlyPlayed(songId);
}
});

// set loop mode
if (box.get(HiveBox.loopModeKey) != null) {
_player.setLoopMode(LoopMode.values[box.get(HiveBox.loopModeKey)]);
}

// set shuffle mode
if (box.get(HiveBox.shuffleModeKey) != null) {
_player.setShuffleModeEnabled(
box.get(HiveBox.shuffleModeKey),
);
}
}

@override
Future<void> load(
MediaItem mediaItem,
List<SongModel> playlist,
) async {
List<SongModel> playlist, {
bool play = true,
}) async {
List<AudioSource> sources = [];

for (var song in playlist) {
Expand Down Expand Up @@ -103,8 +128,47 @@ class JustAudioPlayer implements MusicPlayer {
),
);

// set current playlist
currentPlaylist = playlist;
await _player.play();

// save current playlist
await savePlaylist();

if (play) {
// play the song
await _player.play();
}
}

/// save current playlist to hive
@override
Future savePlaylist() async {
await box.put(
HiveBox.lastPlayedPlaylistKey,
currentPlaylist.map((song) => song.getMap).toList(),
);
}

/// load current playlist from hive
@override
Future<List<SongModel>> loadPlaylist() async {
List<dynamic> playlist = box.get(
HiveBox.lastPlayedPlaylistKey,
defaultValue: List.empty(),
);
return playlist.map((song) => SongModel(song)).toList();
}

@override
Future<void> getSequenceFromPlaylist(
List<SongModel> playlist,
SongModel lastPlayedSong,
) async {
await load(
getMediaItemFromSong(lastPlayedSong),
playlist,
play: false,
);
}

@override
Expand Down Expand Up @@ -198,11 +262,13 @@ class JustAudioPlayer implements MusicPlayer {

@override
Future<void> setLoopMode(LoopMode loopMode) async {
await box.put(HiveBox.loopModeKey, loopMode.index);
await _player.setLoopMode(loopMode);
}

@override
Future<void> setShuffleModeEnabled(bool enabled) async {
await box.put(HiveBox.shuffleModeKey, enabled);
await _player.setShuffleModeEnabled(enabled);
}

Expand Down
13 changes: 8 additions & 5 deletions lib/src/data/services/hive_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ class HiveBox {
static const String boxName = 'myBox';

static const String themeKey = 'theme';

static const String favoriteSongsKey = 'favoriteSongs';
// static const String favoriteArtistsKey = 'favoriteArtists';
// static const String favoriteAlbumsKey = 'favoriteAlbums';

static const String lastPlayedPlaylistKey = 'lastPlayedPlaylist';
static const String recentlyPlayedSongsKey = 'recentlyPlayedSongs';
// static const int maxRecentlyPlayed = 50;
// static const String searchHistoryKey = 'searchHistory';
static const String playlistsKey = 'playlists';
// static const String lastSongKey = 'lastSong';

static const String searchHistoryKey = 'searchHistory';

static const String minSongDurationKey = 'minSongDuration';
static const String minSongSizeKey = 'minSongSize';

static const String songSortTypeKey = 'songSortType';
static const String songOrderTypeKey = 'songOrderType';

static const String shuffleModeKey = 'shuffleMode';
static const String loopModeKey = 'loopMode';
}
4 changes: 2 additions & 2 deletions lib/src/presentation/pages/home/views/songs_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class _SongsViewState extends State<SongsView>
context.read<PlayerBloc>().add(
PlayerLoadSongs(
songs,
sl<JustAudioPlayer>()
sl<MusicPlayer>()
.getMediaItemFromSong(randomSong),
),
);
Expand Down Expand Up @@ -175,7 +175,7 @@ class _SongsViewState extends State<SongsView>
context.read<PlayerBloc>().add(
PlayerLoadSongs(
songs,
sl<JustAudioPlayer>()
sl<MusicPlayer>()
.getMediaItemFromSong(songs[0]),
),
);
Expand Down
2 changes: 2 additions & 0 deletions lib/src/presentation/pages/playlists/recents_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class _RecentsPageState extends State<RecentsPage> {
title: const Text('Recents'),
),
body: Ink(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(
gradient: Themes.getTheme().linearGradient,
),
Expand Down
23 changes: 21 additions & 2 deletions lib/src/presentation/widgets/player_bottom_app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:meloplay/src/core/di/service_locator.dart';
import 'package:meloplay/src/core/router/app_router.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/data/repositories/player_repository.dart';
import 'package:meloplay/src/data/repositories/recents_repository.dart';
import 'package:meloplay/src/presentation/widgets/seek_bar.dart';
import 'package:meloplay/src/presentation/widgets/spinning_disc_animation.dart';
import 'package:on_audio_query/on_audio_query.dart';
Expand All @@ -29,6 +30,8 @@ class _PlayerBottomAppBarState extends State<PlayerBottomAppBar> {
bool isPlaying = false;
bool isExpanded = false;

List<SongModel> playlist = [];

@override
void initState() {
super.initState();
Expand All @@ -46,6 +49,18 @@ class _PlayerBottomAppBarState extends State<PlayerBottomAppBar> {
}
}

Future<void> _getPlaylist() async {
playlist = await player.loadPlaylist();
if (playlist.isEmpty) {
return;
}
// get last played song
SongModel? lastPlayedSong = await sl<RecentsRepository>().fetchLastPlayed();
if (lastPlayedSong != null) {
await player.getSequenceFromPlaylist(playlist, lastPlayedSong);
}
}

@override
Widget build(BuildContext context) {
return SizedBox(
Expand All @@ -54,11 +69,15 @@ class _PlayerBottomAppBarState extends State<PlayerBottomAppBar> {
return StreamBuilder<SequenceState?>(
stream: player.sequenceState,
builder: (context, snapshot) {
SequenceState? sequence;
if (!snapshot.hasData) {
return const SizedBox.shrink();
// if no sequence is loaded, load from hive
_getPlaylist();
return const SizedBox();
} else {
sequence = snapshot.data;
}

final sequence = snapshot.data;
MediaItem mediaItem =
sequence?.sequence[sequence.currentIndex].tag;

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: meloplay
description: 'Meloplay is a local music player app that plays music from your device built with Flutter.'
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.3.4
version: 1.3.5

environment:
sdk: '>=3.4.0 <4.0.0'
Expand Down

0 comments on commit b1247d9

Please sign in to comment.