feat/makepkg + project structure #12
@@ -16,6 +16,12 @@ const isDev = !app.isPackaged;
|
|||||||
|
|
||||||
app.name = "Ultimate Ban Tracker";
|
app.name = "Ultimate Ban Tracker";
|
||||||
|
|
||||||
|
// Force Wayland/Ozone support if on Linux
|
||||||
|
if (process.platform === 'linux') {
|
||||||
|
app.commandLine.appendSwitch('enable-features', 'UseOzonePlatform');
|
||||||
|
app.commandLine.appendSwitch('ozone-platform', 'wayland');
|
||||||
|
}
|
||||||
|
|
||||||
// Load environment variables
|
// Load environment variables
|
||||||
dotenv.config({ path: path.join(app.getAppPath(), '..', '.env') });
|
dotenv.config({ path: path.join(app.getAppPath(), '..', '.env') });
|
||||||
|
|
||||||
@@ -89,35 +95,64 @@ const initBackend = () => {
|
|||||||
|
|
||||||
// --- System Tray ---
|
// --- System Tray ---
|
||||||
const createTray = () => {
|
const createTray = () => {
|
||||||
|
console.log('[Tray] Initializing...');
|
||||||
|
|
||||||
const possiblePaths = [
|
const possiblePaths = [
|
||||||
'/usr/share/pixmaps/ultimate-ban-tracker.png',
|
'/usr/share/pixmaps/ultimate-ban-tracker.png', // Priority 1: System installed
|
||||||
path.join(process.resourcesPath, 'assets-build', 'icon.png'),
|
path.join(process.resourcesPath, 'assets-build', 'icon.png'), // Priority 2: Unpacked resources
|
||||||
path.join(app.getAppPath(), 'assets-build', 'icon.png'),
|
path.join(app.getAppPath(), 'assets-build', 'icon.png'), // Priority 3: Internal ASAR (Fallback)
|
||||||
path.join(__dirname, '..', 'assets-build', 'icon.png')
|
path.join(__dirname, '..', 'assets-build', 'icon.png') // Priority 4: Dev
|
||||||
];
|
];
|
||||||
|
|
||||||
let iconPath = '';
|
let iconPath = '';
|
||||||
for (const p of possiblePaths) { if (p && fs.existsSync(p)) { iconPath = p; break; } }
|
for (const p of possiblePaths) {
|
||||||
|
console.log(`[Tray] Checking path: ${p}`);
|
||||||
|
if (p && fs.existsSync(p)) {
|
||||||
|
iconPath = p;
|
||||||
|
console.log(`[Tray] Found icon at: ${p}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!iconPath) { try { tray = new Tray(nativeImage.createEmpty()); } catch (e) {} return; }
|
if (!iconPath) {
|
||||||
|
console.warn('[Tray] FAILED: No icon file found on disk. Using empty fallback.');
|
||||||
|
try { tray = new Tray(nativeImage.createEmpty()); } catch (e) {}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const icon = nativeImage.createFromPath(iconPath).resize({ width: 16, height: 16 });
|
||||||
|
tray = new Tray(icon);
|
||||||
|
console.log('[Tray] Tray object created successfully');
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(`[Tray] Failed to create Tray object: ${e.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
if (tray) {
|
||||||
const icon = nativeImage.createFromPath(iconPath).resize({ width: 16, height: 16 });
|
|
||||||
tray = new Tray(icon);
|
|
||||||
tray.setToolTip('Ultimate Ban Tracker');
|
tray.setToolTip('Ultimate Ban Tracker');
|
||||||
if (process.platform === 'linux') tray.setIgnoreMouseEvents(false);
|
if (process.platform === 'linux') tray.setIgnoreMouseEvents(false);
|
||||||
tray.on('click', () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } });
|
tray.on('click', () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } });
|
||||||
|
|
||||||
|
// Initial menu build
|
||||||
updateTrayMenu();
|
updateTrayMenu();
|
||||||
|
|
||||||
const config = store.get('serverConfig');
|
const config = store.get('serverConfig');
|
||||||
if (config?.theme) setAppIcon(config.theme);
|
if (config?.theme) setAppIcon(config.theme);
|
||||||
} catch (e: any) { console.error(`[Tray] Error: ${e.message}`); }
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTrayMenu = () => {
|
const updateTrayMenu = () => {
|
||||||
if (!tray) return;
|
if (!tray) {
|
||||||
|
console.warn('[Tray] Cannot update menu: Tray is null');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const accounts = store.get('accounts') as Account[];
|
const accounts = store.get('accounts') as Account[];
|
||||||
const config = store.get('serverConfig');
|
const config = store.get('serverConfig');
|
||||||
const contextMenu = Menu.buildFromTemplate([
|
|
||||||
|
console.log(`[Tray] Building menu with ${accounts.length} accounts...`);
|
||||||
|
|
||||||
|
const menuTemplate: any[] = [
|
||||||
{ label: `Ultimate Ban Tracker v${app.getVersion()}`, enabled: false },
|
{ label: `Ultimate Ban Tracker v${app.getVersion()}`, enabled: false },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{
|
{
|
||||||
@@ -125,34 +160,83 @@ const updateTrayMenu = () => {
|
|||||||
submenu: accounts.length > 0 ? accounts.map(acc => ({
|
submenu: accounts.length > 0 ? accounts.map(acc => ({
|
||||||
label: `${acc.personaName} ${acc.loginName ? `(${acc.loginName})` : ''}`,
|
label: `${acc.personaName} ${acc.loginName ? `(${acc.loginName})` : ''}`,
|
||||||
enabled: !!acc.loginName,
|
enabled: !!acc.loginName,
|
||||||
click: () => handleSwitchAccount(acc.loginName)
|
click: () => {
|
||||||
})) : [{ label: 'No accounts found', enabled: false }]
|
console.log(`[Tray] Switching to account: ${acc.loginName}`);
|
||||||
|
handleSwitchAccount(acc.loginName);
|
||||||
|
}
|
||||||
|
})) : [{ label: 'No accounts tracked', enabled: false }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Sync Now',
|
||||||
|
enabled: !!config?.enabled,
|
||||||
|
click: () => {
|
||||||
|
console.log('[Tray] Manual sync requested');
|
||||||
|
syncAccounts(true);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{ label: 'Sync Now', enabled: !!config?.enabled, click: () => syncAccounts(true) },
|
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ label: 'Show Dashboard', click: () => { if (mainWindow) { mainWindow.show(); mainWindow.focus(); } } },
|
{
|
||||||
{ label: 'Quit', click: () => {
|
label: 'Show Dashboard',
|
||||||
(app as any).isQuitting = true;
|
click: () => {
|
||||||
if (tray) tray.destroy();
|
console.log('[Tray] Showing dashboard');
|
||||||
app.quit();
|
if (mainWindow) {
|
||||||
} }
|
mainWindow.show();
|
||||||
]);
|
mainWindow.focus();
|
||||||
tray.setContextMenu(contextMenu);
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
click: () => {
|
||||||
|
console.log('[Tray] Quitting application via menu');
|
||||||
|
(app as any).isQuitting = true;
|
||||||
|
if (tray) tray.destroy();
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const contextMenu = Menu.buildFromTemplate(menuTemplate);
|
||||||
|
tray.setContextMenu(contextMenu);
|
||||||
|
console.log('[Tray] Menu updated and attached');
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(`[Tray] Failed to build or set context menu: ${e.message}`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const setAppIcon = (themeName: string = 'steam') => {
|
const setAppIcon = (themeName: string = 'steam') => {
|
||||||
|
console.log(`[AppIcon] Setting icon for theme: ${themeName}`);
|
||||||
const possiblePaths = [
|
const possiblePaths = [
|
||||||
path.join(__dirname, '..', 'assets-build', 'icons', `${themeName}.svg`),
|
|
||||||
path.join(app.getAppPath(), 'assets-build', 'icons', `${themeName}.svg`),
|
path.join(app.getAppPath(), 'assets-build', 'icons', `${themeName}.svg`),
|
||||||
|
path.join(__dirname, '..', 'assets-build', 'icons', `${themeName}.svg`),
|
||||||
|
path.join(process.resourcesPath, 'assets-build', 'icons', `${themeName}.svg`),
|
||||||
'/usr/share/pixmaps/ultimate-ban-tracker.png'
|
'/usr/share/pixmaps/ultimate-ban-tracker.png'
|
||||||
];
|
];
|
||||||
|
|
||||||
let iconPath = '';
|
let iconPath = '';
|
||||||
for (const p of possiblePaths) { if (fs.existsSync(p)) { iconPath = p; break; } }
|
for (const p of possiblePaths) { if (p && fs.existsSync(p)) { iconPath = p; break; } }
|
||||||
if (!iconPath) return;
|
|
||||||
const icon = nativeImage.createFromPath(iconPath);
|
if (!iconPath) {
|
||||||
if (tray) tray.setImage(icon.resize({ width: 16, height: 16 }));
|
console.warn(`[AppIcon] No themed icon found for ${themeName}`);
|
||||||
if (mainWindow) mainWindow.setIcon(icon);
|
return;
|
||||||
updateTrayMenu();
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const icon = nativeImage.createFromPath(iconPath);
|
||||||
|
if (tray) {
|
||||||
|
tray.setImage(icon.resize({ width: 16, height: 16 }));
|
||||||
|
console.log('[AppIcon] Tray icon updated');
|
||||||
|
}
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow.setIcon(icon);
|
||||||
|
console.log('[AppIcon] Window icon updated');
|
||||||
|
}
|
||||||
|
// Re-build menu to ensure everything is consistent
|
||||||
|
updateTrayMenu();
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(`[AppIcon] Failed to apply themed icon: ${e.message}`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Steam Logic ---
|
// --- Steam Logic ---
|
||||||
|
|||||||
Reference in New Issue
Block a user