112 lines
3 KiB
Dart
112 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/api/player/player_helper.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();
|
|
}
|
|
}
|