108 lines
2.9 KiB
Dart
108 lines
2.9 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._();
|
||
|
|
||
|
class SysTray with TrayListener {
|
||
|
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;
|
||
|
|
||
|
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: (menuItem) => audioHandler.skipToPrevious()),
|
||
|
playing
|
||
|
? MenuItem(
|
||
|
label: 'Pause'.i18n, onClick: (menuItem) => audioHandler.pause())
|
||
|
: MenuItem(
|
||
|
label: 'Play'.i18n, onClick: (menuItem) => audioHandler.play()),
|
||
|
MenuItem(
|
||
|
label: 'Next'.i18n, onClick: (menuItem) => audioHandler.skipToNext()),
|
||
|
MenuItem.separator(),
|
||
|
MenuItem(
|
||
|
label: 'Show'.i18n,
|
||
|
// we can safely ignore it if it errors, as it's expected
|
||
|
onClick: (menuItem) => windowManager.show().catchError((e) {})),
|
||
|
MenuItem(
|
||
|
label: 'Exit'.i18n,
|
||
|
onClick: (menuItem) 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 onTrayMenuItemClick(MenuItem menuItem) {}
|
||
|
}
|