Pato05
87c9733f51
fix audio service stop on android getTrack backend improvements get new track token when expired move shuffle button into LibraryPlaylists as FAB move favoriteButton next to track title move lyrics button on top of album art search: fix chips, and remove checkbox when selected
111 lines
3 KiB
Dart
111 lines
3 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:audio_service/audio_service.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:freezer/api/player/audio_handler.dart';
|
|
import 'package:freezer/settings.dart';
|
|
import 'package:freezer/translations.i18n.dart';
|
|
import 'package:tray_manager/tray_manager.dart';
|
|
import 'package:window_manager/window_manager.dart';
|
|
|
|
final sysTray = SysTray._();
|
|
|
|
/// Handles system tray and window events
|
|
class SysTray with TrayListener, WindowListener {
|
|
SysTray._();
|
|
|
|
static String getIcon({bool forcePng = false}) {
|
|
if (Platform.isWindows && !forcePng) {
|
|
if (settings.useColorTrayIcon) {
|
|
return 'assets/icon.ico';
|
|
}
|
|
return 'assets/icon_mono_small.ico';
|
|
}
|
|
|
|
if (settings.useColorTrayIcon) {
|
|
return 'assets/icon_small.png';
|
|
}
|
|
|
|
return 'assets/icon_mono_small.png';
|
|
}
|
|
|
|
bool _inited = false;
|
|
Future<void> init() async {
|
|
if (_inited) return;
|
|
_inited = true;
|
|
|
|
windowManager.addListener(this);
|
|
|
|
updateIcon();
|
|
try {
|
|
await trayManager.setToolTip('freezer');
|
|
// ignore: empty_catches
|
|
} catch (e) {}
|
|
|
|
await updateContextMenu();
|
|
|
|
trayManager.addListener(this);
|
|
|
|
playerHelper.playing
|
|
.listen((playing) => updateContextMenu(playing: playing));
|
|
audioHandler.mediaItem
|
|
.listen((mediaItem) => updateContextMenu(mediaItem: mediaItem));
|
|
}
|
|
|
|
Future<void> updateIcon() {
|
|
return trayManager.setIcon(getIcon());
|
|
}
|
|
|
|
Future<void> updateContextMenu({bool? playing, MediaItem? mediaItem}) async {
|
|
playing ??= playerHelper.playing.valueOrNull ?? false;
|
|
mediaItem ??= audioHandler.mediaItem.valueOrNull;
|
|
// create context menu
|
|
final menu = Menu(items: [
|
|
if (mediaItem != null) ...[
|
|
MenuItem(label: mediaItem.title, disabled: true),
|
|
MenuItem(label: mediaItem.artist!, disabled: true),
|
|
],
|
|
MenuItem.separator(),
|
|
MenuItem(
|
|
label: 'Previous'.i18n,
|
|
onClick: (_) => audioHandler.skipToPrevious()),
|
|
playing
|
|
? MenuItem(label: 'Pause'.i18n, onClick: (_) => audioHandler.pause())
|
|
: MenuItem(label: 'Play'.i18n, onClick: (_) => audioHandler.play()),
|
|
MenuItem(label: 'Next'.i18n, onClick: (_) => audioHandler.skipToNext()),
|
|
MenuItem.separator(),
|
|
MenuItem(
|
|
label: 'Show'.i18n,
|
|
// we can safely ignore it if it errors, as it's expected
|
|
onClick: (_) => windowManager.show().catchError((e) {})),
|
|
MenuItem(
|
|
label: 'Exit'.i18n,
|
|
onClick: (_) async {
|
|
await audioHandler.pause();
|
|
SystemNavigator.pop();
|
|
},
|
|
),
|
|
]);
|
|
|
|
// set context menu
|
|
await trayManager.setContextMenu(menu);
|
|
}
|
|
|
|
@override
|
|
void onTrayIconMouseUp() async {
|
|
try {
|
|
await windowManager.show();
|
|
// ignore: empty_catches
|
|
} catch (e) {}
|
|
}
|
|
|
|
@override
|
|
void onTrayIconRightMouseUp() => trayManager.popUpContextMenu();
|
|
|
|
@override
|
|
void onWindowClose() {
|
|
// release resources before closing
|
|
audioHandler.dispose();
|
|
}
|
|
}
|