Files
rmtPocketWatcher/flutter_app/lib/services/window_service.dart
HRiggs 110c5d99a1
Some checks failed
Flutter Release / get-version (push) Successful in 7s
Flutter Release / build-windows (push) Failing after 9s
Flutter Release / create-release (push) Has been cancelled
Flutter Release / build-android (push) Has been cancelled
Signing, Installer, New Workflows
2025-12-15 00:05:29 -05:00

315 lines
8.2 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:window_manager/window_manager.dart';
import 'package:tray_manager/tray_manager.dart';
class WindowService with WindowListener, TrayListener {
static final WindowService _instance = WindowService._internal();
factory WindowService() => _instance;
WindowService._internal();
bool _isInitialized = false;
bool _isMinimizedToTray = false;
BuildContext? _context;
Future<void> initialize({BuildContext? context}) async {
if (_isInitialized) return;
_context = context;
// Initialize window manager
windowManager.addListener(this);
// Initialize system tray
await _initializeTray();
_isInitialized = true;
}
Future<void> _initializeTray() async {
try {
await trayManager.setIcon(
kIsWeb ? '' : 'icon.ico',
isTemplate: false,
);
await trayManager.setToolTip('rmtPocketWatcher - AUEC Price Tracker');
// Create tray menu
Menu menu = Menu(
items: [
MenuItem(
key: 'show_window',
label: 'Show rmtPocketWatcher',
),
MenuItem.separator(),
MenuItem(
key: 'check_updates',
label: 'Check for Updates',
),
MenuItem.separator(),
MenuItem(
key: 'about',
label: 'About',
),
MenuItem.separator(),
MenuItem(
key: 'exit_app',
label: 'Exit',
),
],
);
await trayManager.setContextMenu(menu);
trayManager.addListener(this);
if (kDebugMode) {
print('System tray initialized successfully');
}
} catch (e) {
if (kDebugMode) {
print('Failed to initialize system tray: $e');
}
}
}
// Window controls
Future<void> minimizeWindow() async {
await windowManager.minimize();
}
Future<void> minimizeToTray() async {
await windowManager.hide();
_isMinimizedToTray = true;
if (kDebugMode) {
print('Window minimized to system tray');
}
}
Future<void> showWindow() async {
await windowManager.show();
await windowManager.focus();
_isMinimizedToTray = false;
if (kDebugMode) {
print('Window restored from system tray');
}
}
Future<void> maximizeWindow() async {
bool isMaximized = await windowManager.isMaximized();
if (isMaximized) {
await windowManager.unmaximize();
} else {
await windowManager.maximize();
}
}
Future<void> closeWindow() async {
// Close button should exit the app
await exitApp();
}
Future<void> exitApp() async {
await trayManager.destroy();
await windowManager.destroy();
SystemNavigator.pop();
}
// Window event handlers
@override
void onWindowClose() async {
// Prevent default close behavior
await closeWindow();
}
@override
void onWindowMinimize() async {
// When window is minimized (via minimize button or taskbar), go to tray
await minimizeToTray();
if (kDebugMode) {
print('Window minimized to tray');
}
}
@override
void onWindowRestore() {
_isMinimizedToTray = false;
if (kDebugMode) {
print('Window restored');
}
}
@override
void onWindowMaximize() {
if (kDebugMode) {
print('Window maximized');
}
}
@override
void onWindowUnmaximize() {
if (kDebugMode) {
print('Window unmaximized');
}
}
// Tray event handlers
@override
void onTrayIconMouseDown() async {
// Single click to show/hide window
if (_isMinimizedToTray) {
await showWindow();
} else {
await minimizeToTray();
}
}
@override
void onTrayIconRightMouseDown() async {
// Right click shows context menu (handled automatically)
}
@override
void onTrayMenuItemClick(MenuItem menuItem) async {
switch (menuItem.key) {
case 'show_window':
await showWindow();
break;
case 'check_updates':
await showWindow();
// The update check will be handled by the UI
if (kDebugMode) {
print('Checking for updates from tray menu');
}
break;
case 'about':
await showWindow();
_showAboutDialog();
break;
case 'exit_app':
await exitApp();
break;
}
}
// Update tray tooltip with current status
Future<void> updateTrayTooltip(String status) async {
try {
await trayManager.setToolTip('rmtPocketWatcher - $status');
} catch (e) {
if (kDebugMode) {
print('Failed to update tray tooltip: $e');
}
}
}
// Update tray menu with dynamic content
Future<void> updateTrayMenu({bool hasUpdate = false}) async {
try {
Menu menu = Menu(
items: [
MenuItem(
key: 'show_window',
label: 'Show rmtPocketWatcher',
),
MenuItem.separator(),
MenuItem(
key: 'check_updates',
label: hasUpdate ? '🔄 Update Available!' : 'Check for Updates',
),
MenuItem.separator(),
MenuItem(
key: 'about',
label: 'About',
),
MenuItem.separator(),
MenuItem(
key: 'exit_app',
label: 'Exit',
),
],
);
await trayManager.setContextMenu(menu);
} catch (e) {
if (kDebugMode) {
print('Failed to update tray menu: $e');
}
}
}
// Getters
bool get isMinimizedToTray => _isMinimizedToTray;
bool get isInitialized => _isInitialized;
void _showAboutDialog() {
if (_context != null) {
// Import the about dialog dynamically to avoid circular imports
showDialog(
context: _context!,
builder: (context) {
// We'll create a simple about dialog here to avoid import issues
return AlertDialog(
backgroundColor: const Color(0xFF1A1F3A),
title: const Row(
children: [
Icon(Icons.analytics, color: Color(0xFF50E3C2), size: 32),
SizedBox(width: 12),
Text('rmtPocketWatcher', style: TextStyle(color: Colors.white)),
],
),
content: const Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Star Citizen AUEC Price Tracker',
style: TextStyle(color: Colors.white70, fontSize: 14),
),
SizedBox(height: 8),
Text(
'Developed by Lambda Banking Conglomerate',
style: TextStyle(color: Colors.white70, fontSize: 12),
),
SizedBox(height: 16),
Text(
'Features:',
style: TextStyle(
color: Color(0xFF50E3C2),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text('• Real-time AUEC price tracking', style: TextStyle(color: Colors.white70, fontSize: 12)),
Text('• Multiple vendor monitoring', style: TextStyle(color: Colors.white70, fontSize: 12)),
Text('• Historical price charts', style: TextStyle(color: Colors.white70, fontSize: 12)),
Text('• Price alerts & notifications', style: TextStyle(color: Colors.white70, fontSize: 12)),
Text('• System tray integration', style: TextStyle(color: Colors.white70, fontSize: 12)),
],
),
actions: [
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF50E3C2),
foregroundColor: Colors.black,
),
child: const Text('Close'),
),
],
);
},
);
}
}
// Cleanup
void dispose() {
windowManager.removeListener(this);
trayManager.removeListener(this);
}
}