mirror of
https://github.com/smartfrigde/armcord.git
synced 2026-08-19 06:03:22 +00:00
Compare commits
3 commits
0a022f1490
...
022676cf65
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
022676cf65 |
||
|
|
7b204d4481 |
||
|
|
d575d32865 |
4 changed files with 136 additions and 19 deletions
|
|
@ -85,6 +85,17 @@ export const config: Configuration = {
|
|||
electronDownload: {
|
||||
cache: ".cache",
|
||||
},
|
||||
|
||||
electronFuses: {
|
||||
runAsNode: false,
|
||||
enableCookieEncryption: false,
|
||||
enableNodeOptionsEnvironmentVariable: false,
|
||||
enableNodeCliInspectArguments: false,
|
||||
enableEmbeddedAsarIntegrityValidation: false,
|
||||
onlyLoadAppFromAsar: true,
|
||||
loadBrowserProcessSpecificV8Snapshot: false,
|
||||
grantFileProtocolExtraPrivileges: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
2
src/@types/windowState.d.ts
vendored
2
src/@types/windowState.d.ts
vendored
|
|
@ -4,4 +4,6 @@ export interface WindowState {
|
|||
x: number;
|
||||
y: number;
|
||||
isMaximized: boolean;
|
||||
displayId?: number;
|
||||
displayScaleFactor?: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
dialog,
|
||||
type MessageBoxOptions,
|
||||
nativeImage,
|
||||
screen,
|
||||
shell,
|
||||
} from "electron";
|
||||
import contextMenu from "electron-context-menu";
|
||||
|
|
@ -29,6 +30,51 @@ import { registerVenmicIpc } from "./venmic.js";
|
|||
export let mainWindows: BrowserWindow[] = [];
|
||||
export let inviteWindow: BrowserWindow;
|
||||
|
||||
function getStoredWindowBounds(): BrowserWindowConstructorOptions {
|
||||
const width = getWindowState("width") ?? 835;
|
||||
const height = getWindowState("height") ?? 600;
|
||||
const x = getWindowState("x");
|
||||
const y = getWindowState("y");
|
||||
|
||||
if (x === undefined || y === undefined) {
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
};
|
||||
}
|
||||
|
||||
// Return the stored window coordinates as-is.
|
||||
// Restore uses setPosition/setSize for a direct API roundtrip.
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
x,
|
||||
y,
|
||||
};
|
||||
}
|
||||
|
||||
// Save window bounds using the same API family we restore with.
|
||||
// This avoids coordinate-space mismatches caused by getNormalBounds()/setBounds() across DPI setups.
|
||||
function saveWindowState(win: BrowserWindow): void {
|
||||
try {
|
||||
const [x, y] = win.getPosition();
|
||||
const [width, height] = win.getSize();
|
||||
const display = screen.getDisplayNearestPoint({ x, y });
|
||||
|
||||
setWindowState({
|
||||
width,
|
||||
height,
|
||||
isMaximized: win.isMaximized(),
|
||||
x,
|
||||
y,
|
||||
displayId: display.id,
|
||||
displayScaleFactor: display.scaleFactor,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("[Window] Failed to save window state:", e);
|
||||
}
|
||||
}
|
||||
|
||||
contextMenu({
|
||||
showSaveImageAs: true,
|
||||
showCopyImageAddress: true,
|
||||
|
|
@ -291,6 +337,10 @@ function doAfterDefiningTheWindow(passedWindow: BrowserWindow): void {
|
|||
passedWindow.destroy();
|
||||
}
|
||||
if (getConfig("minimizeToTray") && !forceQuit) {
|
||||
// Save state when hiding to tray so we persist display metadata
|
||||
try {
|
||||
saveWindowState(passedWindow);
|
||||
} catch {}
|
||||
e.preventDefault();
|
||||
passedWindow.hide();
|
||||
} else if (!getConfig("minimizeToTray")) {
|
||||
|
|
@ -299,17 +349,22 @@ function doAfterDefiningTheWindow(passedWindow: BrowserWindow): void {
|
|||
});
|
||||
app.on("before-quit", () => {
|
||||
stopRPC();
|
||||
const [width, height] = passedWindow.getSize();
|
||||
setWindowState({
|
||||
width,
|
||||
height,
|
||||
isMaximized: passedWindow.isMaximized(),
|
||||
x: passedWindow.getPosition()[0],
|
||||
y: passedWindow.getPosition()[1],
|
||||
});
|
||||
try {
|
||||
// Ensure current window state is saved with display info
|
||||
if (passedWindow && !passedWindow.isDestroyed()) saveWindowState(passedWindow);
|
||||
} catch (e) {
|
||||
console.log("[Window] before-quit save failed:", e);
|
||||
}
|
||||
setForceQuit(true);
|
||||
});
|
||||
|
||||
// also save on minimize in case of session shutdowns
|
||||
passedWindow.on("minimize", () => {
|
||||
try {
|
||||
saveWindowState(passedWindow);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
passedWindow.on("focus", () => {
|
||||
void passedWindow.webContents.executeJavaScript(`document.body.removeAttribute("unFocused");`);
|
||||
});
|
||||
|
|
@ -331,6 +386,48 @@ function doAfterDefiningTheWindow(passedWindow: BrowserWindow): void {
|
|||
}
|
||||
|
||||
registerGlobalKeybinds();
|
||||
// Persist bounds on move/resize with debounce to avoid frequent writes
|
||||
let _saveTimer: NodeJS.Timeout | null = null;
|
||||
const queueSave = () => {
|
||||
if (_saveTimer) clearTimeout(_saveTimer);
|
||||
_saveTimer = setTimeout(() => {
|
||||
try {
|
||||
saveWindowState(passedWindow);
|
||||
} catch (e) {
|
||||
console.log("[Window] queueSave failed:", e);
|
||||
}
|
||||
_saveTimer = null;
|
||||
}, 500);
|
||||
};
|
||||
passedWindow.on("move", queueSave);
|
||||
passedWindow.on("resize", queueSave);
|
||||
|
||||
// Fallback: periodic poll to detect bounds changes.
|
||||
// Compare raw getNormalBounds() values to detect movement;
|
||||
// saveWindowState normalizes to DIP where needed.
|
||||
let lastPolledBounds: { x: number; y: number; width: number; height: number } | null = null;
|
||||
const pollInterval = setInterval(() => {
|
||||
try {
|
||||
if (passedWindow.isDestroyed()) {
|
||||
clearInterval(pollInterval);
|
||||
return;
|
||||
}
|
||||
const { x, y, width, height } = passedWindow.getNormalBounds();
|
||||
if (
|
||||
!lastPolledBounds ||
|
||||
lastPolledBounds.x !== x ||
|
||||
lastPolledBounds.y !== y ||
|
||||
lastPolledBounds.width !== width ||
|
||||
lastPolledBounds.height !== height
|
||||
) {
|
||||
lastPolledBounds = { x, y, width, height };
|
||||
saveWindowState(passedWindow);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore transient errors
|
||||
}
|
||||
}, 1000);
|
||||
passedWindow.on("closed", () => clearInterval(pollInterval));
|
||||
switch (getConfig("channel")) {
|
||||
case "stable":
|
||||
void passedWindow.loadURL("https://discord.com/app");
|
||||
|
|
@ -352,11 +449,11 @@ function doAfterDefiningTheWindow(passedWindow: BrowserWindow): void {
|
|||
}
|
||||
|
||||
export function createWindow() {
|
||||
const storedBounds = getStoredWindowBounds();
|
||||
const browserWindowOptions: BrowserWindowConstructorOptions = {
|
||||
width: getWindowState("width") ?? 835,
|
||||
height: getWindowState("height") ?? 600,
|
||||
x: getWindowState("x"),
|
||||
y: getWindowState("y"),
|
||||
// Use safe defaults for constructor; actual bounds applied via setBounds() below
|
||||
width: 835,
|
||||
height: 600,
|
||||
title: "Legcord",
|
||||
show: false,
|
||||
darkTheme: true,
|
||||
|
|
@ -417,6 +514,13 @@ export function createWindow() {
|
|||
break;
|
||||
}
|
||||
const mainWindow = new BrowserWindow(browserWindowOptions);
|
||||
|
||||
// Restore by position + size directly to match saveWindowState roundtrip.
|
||||
if (storedBounds.x !== undefined && storedBounds.y !== undefined) {
|
||||
mainWindow.setPosition(storedBounds.x, storedBounds.y);
|
||||
mainWindow.setSize(storedBounds.width, storedBounds.height);
|
||||
}
|
||||
|
||||
mainWindows.push(mainWindow);
|
||||
doAfterDefiningTheWindow(mainWindow);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,16 @@
|
|||
background-color 0.15s ease,
|
||||
transform 0.1s ease,
|
||||
border-color 0.25s ease;
|
||||
border: 2px solid transparent;
|
||||
border: 2px solid var(--background-modifier-accent);
|
||||
position: relative;
|
||||
user-select: none;
|
||||
overflow: visible;
|
||||
background: var(--background-secondary);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
background-color: var(--background-modifier-hover);
|
||||
border-color: var(--background-modifier-selected);
|
||||
}
|
||||
|
||||
.card:active {
|
||||
|
|
@ -25,11 +27,11 @@
|
|||
|
||||
.cardSelected {
|
||||
border-color: var(--brand-experiment-560);
|
||||
background-color: color-mix(in srgb, var(--brand-experiment-560) 10%, transparent);
|
||||
background-color: color-mix(in srgb, var(--brand-experiment-560) 12%, var(--background-secondary));
|
||||
}
|
||||
|
||||
.cardSelected:hover {
|
||||
background-color: color-mix(in srgb, var(--brand-experiment-560) 16%, transparent);
|
||||
background-color: color-mix(in srgb, var(--brand-experiment-560) 18%, var(--background-secondary));
|
||||
}
|
||||
|
||||
.checkBadge {
|
||||
|
|
@ -89,8 +91,7 @@
|
|||
transition:
|
||||
opacity 0.2s ease,
|
||||
filter 0.2s ease;
|
||||
opacity: 0.55;
|
||||
filter: brightness(0.85);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.thumbnailSelected {
|
||||
|
|
@ -105,8 +106,7 @@
|
|||
}
|
||||
|
||||
.card:hover .thumbnailUnselected {
|
||||
opacity: 0.75;
|
||||
filter: brightness(0.95);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.name {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue