Skip to content

Commit

Permalink
Added feature to restore last playback session #121
Browse files Browse the repository at this point in the history
  • Loading branch information
anandnet committed Feb 11, 2024
1 parent baab470 commit d33afef
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 25 deletions.
15 changes: 11 additions & 4 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class MyApp extends StatelessWidget {
SystemChannels.lifecycle.setMessageHandler((msg) async {
if (msg == "AppLifecycleState.resumed") {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
} else if (msg == "AppLifecycleState.detached") {
if (Hive.box("AppPrefs").get('restrorePlaybackSession') ?? false) {
Get.find<AudioHandler>().customAction("saveSession");
}
}
return null;
});
Expand All @@ -58,8 +62,9 @@ class MyApp extends StatelessWidget {
Hive.box("AppPrefs").get('currentAppLanguageCode') ?? "en"),
fallbackLocale: const Locale("en"),
builder: (context, child) {
final scale =
MediaQuery.of(context).textScaler.clamp(minScaleFactor:1.0,maxScaleFactor: 1.1);
final scale = MediaQuery.of(context)
.textScaler
.clamp(minScaleFactor: 1.0, maxScaleFactor: 1.1);
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaler: scale),
child: child!,
Expand Down Expand Up @@ -89,9 +94,11 @@ Future<void> startApplicationServices() async {
initHive() async {
String applicationDataDirectoryPath;
if (GetPlatform.isDesktop) {
applicationDataDirectoryPath = "${(await getApplicationSupportDirectory()).path}/db";
applicationDataDirectoryPath =
"${(await getApplicationSupportDirectory()).path}/db";
} else {
applicationDataDirectoryPath = (await getApplicationDocumentsDirectory()).path;
applicationDataDirectoryPath =
(await getApplicationDocumentsDirectory()).path;
}
await Hive.initFlutter(applicationDataDirectoryPath);
await Hive.openBox("SongsCache");
Expand Down
44 changes: 41 additions & 3 deletions lib/services/audio_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {

@override
Future<void> play() async {
if (currentSongUrl == null) {
if (currentSongUrl == null || (GetPlatform.isDesktop && (_player.duration == null || _player.duration?.inMilliseconds==0))) {
await customAction("playByIndex", {'index': currentIndex});
return;
}
Expand Down Expand Up @@ -340,11 +340,12 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
await _player.dispose();
super.stop();
} else if (name == 'playByIndex') {
final bool restoreSession = extras!['restoreSession'] ?? false;
isSongLoading = true;
if (_playList.children.isNotEmpty) {
await _playList.clear();
}
final songIndex = extras!['index'];
final songIndex = extras['index'];
currentIndex = songIndex;
final isNewUrlReq = extras['newUrl'] ?? false;
final currentSong = queue.value[currentIndex];
Expand All @@ -359,7 +360,25 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
playbackState.add(playbackState.value.copyWith(queueIndex: currentIndex));
await _playList.add(_createAudioSource(currentSong));
isSongLoading = false;
await _player.play();

if (restoreSession) {
if (!GetPlatform.isDesktop) {
final position = extras['position'];
await _player.load();
await _player.seek(
Duration(
milliseconds: position,
),
);
await _player.seek(
Duration(
milliseconds: position,
),
);
}
} else {
await _player.play();
}
if (currentIndex == 0) {
cacheNextSongUrl(offset: 1);
}
Expand Down Expand Up @@ -435,6 +454,24 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {
queue.add(currentQueue);
} else if (name == 'openEqualizer') {
await DeviceEqualizer().open(_player.androidAudioSessionId!);
} else if (name == "saveSession") {
await saveSessionData();
}
}

Future<void> saveSessionData() async {
final currQueue = queue.value;
if (currQueue.isNotEmpty) {
final queueData =
currQueue.map((e) => MediaItemBuilder.toJson(e)).toList();
final currIndex = currentIndex ?? 0;
final position = _player.position.inMilliseconds;
final prevSessionData = await Hive.openBox("prevSessionData");
await prevSessionData.clear();
await prevSessionData.putAll(
{"queue": queueData, "position": position, "index": currIndex});
await prevSessionData.close();
printINFO("Saved session data");
}
}

Expand All @@ -449,6 +486,7 @@ class MyAudioHandler extends BaseAudioHandler with GetxServiceMixin {

@override
Future<void> stop() async {
//await saveSessionData();
await _player.stop();
return super.stop();
}
Expand Down
22 changes: 9 additions & 13 deletions lib/ui/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,15 @@ class Home extends StatelessWidget {
endDrawer: Container(
constraints: const BoxConstraints(maxWidth: 600),
decoration: BoxDecoration(
borderRadius:
const BorderRadius.only(topLeft: Radius.circular(10)),
border: Border(
left: BorderSide(
color: Theme.of(context).colorScheme.secondary),
top: BorderSide(
color: Theme.of(context).colorScheme.secondary),
bottom: BorderSide(
width: 0,
color: Theme.of(context).colorScheme.secondary),
right: BorderSide(
width: 0,
color: Theme.of(context).colorScheme.secondary))),
borderRadius:
const BorderRadius.only(topLeft: Radius.circular(10)),
border: Border(
left: BorderSide(
color: Theme.of(context).colorScheme.secondary),
top: BorderSide(
color: Theme.of(context).colorScheme.secondary),
),
),
margin: const EdgeInsets.only(
top: 5,
bottom: 106,
Expand Down
29 changes: 27 additions & 2 deletions lib/ui/player/player_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class PlayerController extends GetxController {
if (GetPlatform.isWindows) {
Get.put(WindowsAudioService());
}
_restorePrevSession();
super.onReady();
}

Expand Down Expand Up @@ -208,6 +209,29 @@ class PlayerController extends GetxController {
});
}

Future<void> _restorePrevSession() async {
final restrorePrevSessionEnabled =
Hive.box("AppPrefs").get("restrorePlaybackSession") ?? false;
if (restrorePrevSessionEnabled) {
final prevSessionData = await Hive.openBox("prevSessionData");
if (prevSessionData.keys.isNotEmpty) {
final songList = (prevSessionData.get("queue") as List)
.map((e) => MediaItemBuilder.fromJson(e))
.toList();
final int currentIndex = prevSessionData.get("index");
final int position = prevSessionData.get("position");
prevSessionData.close();
await _audioHandler.addQueueItems(songList);
_playerPanelCheck(restoreSession: true);
await _audioHandler.customAction("playByIndex", {
"index": currentIndex,
"position": position,
"restoreSession": true
});
}
}
}

///pushSongToPlaylist method clear previous song queue, plays the tapped song and push related
///songs into Queue
Future<void> pushSongToQueue(MediaItem? mediaItem,
Expand Down Expand Up @@ -333,9 +357,10 @@ class PlayerController extends GetxController {
}
}

void _playerPanelCheck() {
void _playerPanelCheck({bool restoreSession = false}) {
final isWideScreen = Get.size.width > 800;
if (!isWideScreen && playerPanelController.isAttached) {
if ((!isWideScreen && playerPanelController.isAttached) &&
!restoreSession) {
playerPanelController.open();
}

Expand Down
11 changes: 11 additions & 0 deletions lib/ui/screens/Settings/settings_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,17 @@ class SettingsScreen extends StatelessWidget {
),
)
: const SizedBox.shrink()),
ListTile(
contentPadding: const EdgeInsets.only(left: 5, right: 10),
title: Text("restoreLastPlaybackSession".tr),
subtitle: Text("restoreLastPlaybackSessionDes".tr,
style: Theme.of(context).textTheme.bodyMedium),
trailing: Obx(
() => Switch(
value: settingsController.restorePlaybackSession.value,
onChanged:
settingsController.toggleRestorePlaybackSession),
)),
if (!isDesktop)
ListTile(
contentPadding:
Expand Down
10 changes: 9 additions & 1 deletion lib/ui/screens/Settings/settings_screen_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class SettingsScreenController extends GetxController {
final hideDloc = true.obs;
final isBottomNavBarEnabled = false.obs;
final backgroundPlayEnabled = true.obs;
final restorePlaybackSession = false.obs;
final currentVersion = "V1.8.0";

@override
Expand Down Expand Up @@ -73,6 +74,8 @@ class SettingsScreenController extends GetxController {
cacheSongs.value = setBox.get('cacheSongs');
themeModetype.value = ThemeType.values[setBox.get('themeModeType')];
skipSilenceEnabled.value = setBox.get("skipSilenceEnabled");
restorePlaybackSession.value =
setBox.get("restrorePlaybackSession") ?? false;
streamingQuality.value =
AudioQuality.values[setBox.get('streamingQuality')];
backgroundPlayEnabled.value = setBox.get("backgroundPlayEnabled") ?? true;
Expand Down Expand Up @@ -189,7 +192,12 @@ class SettingsScreenController extends GetxController {
skipSilenceEnabled.value = val;
}

void toggleBackgroundPlay(bool val){
void toggleRestorePlaybackSession(bool val) {
setBox.put("restrorePlaybackSession", val);
restorePlaybackSession.value = val;
}

void toggleBackgroundPlay(bool val) {
setBox.put('backgroundPlayEnabled', val);
backgroundPlayEnabled.value = val;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/utils/get_localization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,9 @@ class Languages extends Translations {
"trending": "Trending",
"topmusicvideos": "Top Music Videos",
"basedOnLast": "Based on last interaction",
"restoreLastPlaybackSession": "Restore last playback session",
"restoreLastPlaybackSessionDes":
"Automatically restore the last playback session on app start",
"homeContentCount": "Home content count",
"homeContentCountDes":
"Select the number of initial homescreen-content(approx). Lesser results faster loading",
Expand Down
17 changes: 15 additions & 2 deletions lib/utils/system_tray.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:io';

import 'package:audio_service/audio_service.dart';
import 'package:get/get.dart';
import 'package:harmonymusic/ui/player/player_controller.dart';
import 'package:harmonymusic/ui/screens/Settings/settings_screen_controller.dart';
Expand Down Expand Up @@ -62,7 +63,15 @@ class DesktopSystemTray extends GetxService {
}),
MenuSeparator(),
MenuItemLabel(
label: 'Quit', onClicked: (menuItem) => exit(0)),
label: 'Quit',
onClicked: (menuItem) async {
if (Get.find<SettingsScreenController>()
.restorePlaybackSession
.isTrue) {
await Get.find<AudioHandler>().customAction("saveSession");
}
exit(0);
}),
]);

// set context menu
Expand Down Expand Up @@ -95,11 +104,15 @@ class DesktopSystemTray extends GetxService {
class CloseWindowListener extends WindowListener {
@override
Future<void> onWindowClose() async {
if (Get.find<SettingsScreenController>().backgroundPlayEnabled.isTrue &&
final settingsScrnController = Get.find<SettingsScreenController>();
if (settingsScrnController.backgroundPlayEnabled.isTrue &&
Get.find<PlayerController>().buttonState.value ==
PlayButtonState.playing) {
await windowManager.hide();
} else {
if (settingsScrnController.restorePlaybackSession.isTrue) {
await Get.find<AudioHandler>().customAction("saveSession");
}
exit(0);
}
}
Expand Down
2 changes: 2 additions & 0 deletions localization/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
"trending": "Trending",
"topmusicvideos": "Top Music Videos",
"basedOnLast": "Based on last interaction",
"restoreLastPlaybackSession": "Restore last playback session",
"restoreLastPlaybackSessionDes": "Automatically restore the last playback session on app start",
"homeContentCount": "Home content count",
"homeContentCountDes": "Select the number of initial homescreen-content(approx). Lesser results faster loading",
"enableBottomNav": "Bottom nav bar",
Expand Down

0 comments on commit d33afef

Please sign in to comment.