freezer/lib/api/player/systray.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();
}
}