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 initialize({BuildContext? context}) async { if (_isInitialized) return; _context = context; // Initialize window manager windowManager.addListener(this); // Initialize system tray await _initializeTray(); _isInitialized = true; } Future _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 minimizeWindow() async { await windowManager.minimize(); } Future minimizeToTray() async { await windowManager.hide(); _isMinimizedToTray = true; if (kDebugMode) { print('Window minimized to system tray'); } } Future showWindow() async { await windowManager.show(); await windowManager.focus(); _isMinimizedToTray = false; if (kDebugMode) { print('Window restored from system tray'); } } Future maximizeWindow() async { bool isMaximized = await windowManager.isMaximized(); if (isMaximized) { await windowManager.unmaximize(); } else { await windowManager.maximize(); } } Future closeWindow() async { // Close button should exit the app await exitApp(); } Future 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 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 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); } }