From 8f18e05a10ca3c8a698076240308cc5dbfbacdbe Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Sat, 21 Feb 2026 05:28:24 +0100 Subject: [PATCH] fix: improve Linux tray robustness by using system pixmaps and adding libappindicator dependency --- PKGBUILD | 2 +- frontend/electron/main.ts | 87 ++++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 3d4437e..effc884 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -6,7 +6,7 @@ pkgdesc="Professional Steam Account Manager & Ban Tracker" arch=('x86_64') url="https://narl.io" license=('custom:Personal Use and Non-Commercial') -depends=('electron' 'nodejs' 'npm' 'libxss' 'nss' 'libxtst') +depends=('electron' 'nodejs' 'npm' 'libxss' 'nss' 'libxtst' 'libappindicator-gtk3') makedepends=('imagemagick') source=("ultimate-ban-tracker-${pkgver}.tar.gz::https://git.narl.io/nvrl/ultimate-ban-tracker/archive/v${pkgver}.tar.gz") sha256sums=('SKIP') diff --git a/frontend/electron/main.ts b/frontend/electron/main.ts index d744acc..dcd5d31 100644 --- a/frontend/electron/main.ts +++ b/frontend/electron/main.ts @@ -93,40 +93,23 @@ const initBackend = () => { // --- System Tray --- const createTray = () => { - // Try to find the icon in various standard locations const possiblePaths = [ - path.join(__dirname, '..', 'assets-build'), // Dev - path.join(process.resourcesPath, 'assets-build'), // Packaged (External) - path.join(app.getAppPath(), 'dist', 'assets-build'), // Packaged (Internal dist) - path.join(app.getAppPath(), 'assets-build') // Packaged (Internal root) + '/usr/share/pixmaps/ultimate-ban-tracker.png', // System installed (highest priority) + path.join(__dirname, '..', 'assets-build', 'icon.png'), + path.join(__dirname, '..', 'assets-build', 'icon.svg'), + path.join(process.resourcesPath, 'assets-build', 'icon.png'), + path.join(app.getAppPath(), 'assets-build', 'icon.png') ]; - let assetsDir = ''; - for (const p of possiblePaths) { - if (fs.existsSync(p)) { - assetsDir = p; - break; - } - } - - const possibleIcons = ['icon.png', 'icon.svg']; let iconPath = ''; - - if (assetsDir) { - for (const name of possibleIcons) { - const fullPath = path.join(assetsDir, name); - if (fs.existsSync(fullPath)) { - iconPath = fullPath; - break; - } - } + for (const p of possiblePaths) { + if (fs.existsSync(p)) { iconPath = p; break; } } - console.log(`[Tray] Resolved assets directory: ${assetsDir || 'NOT FOUND'}`); - console.log(`[Tray] Attempting to initialize with icon: ${iconPath || 'NONE FOUND'}`); + console.log(`[Tray] Resolved icon path: ${iconPath || 'NONE FOUND'}`); if (!iconPath) { - console.warn(`[Tray] FAILED: No valid icon found in searched paths.`); + console.warn(`[Tray] FAILED: No valid icon found.`); return; } @@ -134,22 +117,34 @@ const createTray = () => { const icon = nativeImage.createFromPath(iconPath).resize({ width: 16, height: 16 }); tray = new Tray(icon); tray.setToolTip('Ultimate Ban Tracker'); + + // Linux Fix: Some DEs need this to show the menu correctly + if (process.platform === 'linux') { + tray.setIgnoreMouseEvents(false); + } + tray.on('click', () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } }); - // Load initial themed icon + // Load initial themed icon if possible const config = store.get('serverConfig'); if (config?.theme) { setAppIcon(config.theme); } else { - updateTrayMenu(); // Fallback to refresh menu + updateTrayMenu(); } - } catch (e) { } + console.log(`[Tray] Successfully initialized`); + } catch (e: any) { + console.error(`[Tray] Error: ${e.message}`); + } }; const updateTrayMenu = () => { if (!tray) return; const accounts = store.get('accounts') as Account[]; const config = store.get('serverConfig'); + + console.log(`[Tray] Building menu with ${accounts.length} accounts`); + const contextMenu = Menu.buildFromTemplate([ { label: `Ultimate Ban Tracker v${app.getVersion()}`, enabled: false }, { type: 'separator' }, @@ -158,34 +153,40 @@ const updateTrayMenu = () => { submenu: accounts.length > 0 ? accounts.map(acc => ({ label: `${acc.personaName} ${acc.loginName ? `(${acc.loginName})` : ''}`, enabled: !!acc.loginName, - click: () => handleSwitchAccount(acc.loginName) + click: () => { + console.log(`[Tray] Switching to ${acc.loginName}`); + handleSwitchAccount(acc.loginName); + } })) : [{ label: 'No accounts found', enabled: false }] }, { label: 'Sync Now', enabled: !!config?.enabled, click: () => syncAccounts(true) }, { type: 'separator' }, - { label: 'Show Dashboard', click: () => { if (mainWindow) mainWindow.show(); } }, + { label: 'Show Dashboard', click: () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } } }, { label: 'Quit', click: () => { (app as any).isQuitting = true; app.quit(); } } ]); tray.setContextMenu(contextMenu); }; const setAppIcon = (themeName: string = 'steam') => { - const assetsDir = path.join(__dirname, '..', 'assets-build', 'icons'); - const iconPath = path.join(assetsDir, `${themeName}.svg`); + // Check system icons folder first on Linux + const possiblePaths = [ + path.join(__dirname, '..', 'assets-build', 'icons', `${themeName}.svg`), + path.join(app.getAppPath(), 'assets-build', 'icons', `${themeName}.svg`), + '/usr/share/pixmaps/ultimate-ban-tracker.png' // Global fallback + ]; + + let iconPath = ''; + for (const p of possiblePaths) { + if (fs.existsSync(p)) { iconPath = p; break; } + } - if (!fs.existsSync(iconPath)) return; + if (!iconPath) return; const icon = nativeImage.createFromPath(iconPath); + if (tray) tray.setImage(icon.resize({ width: 16, height: 16 })); + if (mainWindow) mainWindow.setIcon(icon); - // Update Tray - if (tray) { - tray.setImage(icon.resize({ width: 16, height: 16 })); - } - - // Update Main Window - if (mainWindow) { - mainWindow.setIcon(icon); - } + updateTrayMenu(); // Always rebuild menu after icon update to ensure it's fresh }; // --- Steam Logic ---