앱을 종료할 때 - 전체 화면 모드 상태 여부, 화면 크기, 화면 위치 정보를 저장
This commit is contained in:
@@ -29,6 +29,7 @@ assets/
|
|||||||
src/
|
src/
|
||||||
├── main/
|
├── main/
|
||||||
│ ├── index.js # Main process entry point; app.setName(), BrowserWindow, registerAll()
|
│ ├── index.js # Main process entry point; app.setName(), BrowserWindow, registerAll()
|
||||||
|
│ ├── config.js # Shared userData/config.json read/write helpers
|
||||||
│ └── ipc/
|
│ └── ipc/
|
||||||
│ ├── index.js # registerAll(mainWindow) — delegates to folder and files modules
|
│ ├── index.js # registerAll(mainWindow) — delegates to folder and files modules
|
||||||
│ ├── file-utils.js # Shared main-process file helpers: image listing/data URLs,
|
│ ├── file-utils.js # Shared main-process file helpers: image listing/data URLs,
|
||||||
@@ -189,4 +190,4 @@ Global shortcuts are registered in `keyboard.js`. They do not fire while any `.m
|
|||||||
|
|
||||||
**Build output:** `electron-builder` targets DMG for arm64 and x64.
|
**Build output:** `electron-builder` targets DMG for arm64 and x64.
|
||||||
|
|
||||||
**Config persistence:** `app.getPath('userData')/config.json`에 `lastFolder`, `previewOn` 저장.
|
**Config persistence:** `app.getPath('userData')/config.json`에 `lastFolder`, `previewOn`, `sidebarWidth`, `windowState` 저장. `windowState` includes fullscreen status and normal window bounds (`x`, `y`, `width`, `height`) and is restored on startup if the saved bounds overlap an available display.
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
const { app } = require('electron');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const configPath = path.join(app.getPath('userData'), 'config.json');
|
||||||
|
|
||||||
|
function readConfig() {
|
||||||
|
try {
|
||||||
|
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeConfig(data) {
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(configPath, JSON.stringify(data, null, 2));
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateConfig(updater) {
|
||||||
|
const cfg = readConfig();
|
||||||
|
updater(cfg);
|
||||||
|
writeConfig(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
readConfig,
|
||||||
|
updateConfig,
|
||||||
|
writeConfig,
|
||||||
|
};
|
||||||
+44
-3
@@ -1,15 +1,19 @@
|
|||||||
const { app, BrowserWindow } = require('electron');
|
const { app, BrowserWindow, screen } = require('electron');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { registerAll } = require('./ipc');
|
const { registerAll } = require('./ipc');
|
||||||
|
const { readConfig, updateConfig } = require('./config');
|
||||||
|
|
||||||
app.setName('Photo Renamer');
|
app.setName('Photo Renamer');
|
||||||
|
|
||||||
let mainWindow;
|
let mainWindow;
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
|
const windowState = getSavedWindowState();
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
width: 1200,
|
x: windowState.bounds?.x,
|
||||||
height: 820,
|
y: windowState.bounds?.y,
|
||||||
|
width: windowState.bounds?.width || 1200,
|
||||||
|
height: windowState.bounds?.height || 820,
|
||||||
minWidth: 900,
|
minWidth: 900,
|
||||||
minHeight: 600,
|
minHeight: 600,
|
||||||
titleBarStyle: 'hiddenInset',
|
titleBarStyle: 'hiddenInset',
|
||||||
@@ -27,8 +31,11 @@ function createWindow() {
|
|||||||
|
|
||||||
mainWindow.once('ready-to-show', () => {
|
mainWindow.once('ready-to-show', () => {
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
|
if (windowState.isFullScreen) mainWindow.setFullScreen(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mainWindow.on('close', saveWindowState);
|
||||||
|
|
||||||
mainWindow.on('enter-full-screen', () => {
|
mainWindow.on('enter-full-screen', () => {
|
||||||
mainWindow.webContents.send('fullscreen-change', true);
|
mainWindow.webContents.send('fullscreen-change', true);
|
||||||
});
|
});
|
||||||
@@ -37,6 +44,40 @@ function createWindow() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSavedWindowState() {
|
||||||
|
const cfg = readConfig();
|
||||||
|
const state = cfg.windowState || {};
|
||||||
|
const bounds = isUsableBounds(state.bounds) ? state.bounds : null;
|
||||||
|
return {
|
||||||
|
bounds,
|
||||||
|
isFullScreen: state.isFullScreen === true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUsableBounds(bounds) {
|
||||||
|
if (!bounds) return false;
|
||||||
|
const values = [bounds.x, bounds.y, bounds.width, bounds.height];
|
||||||
|
if (!values.every(Number.isFinite)) return false;
|
||||||
|
if (bounds.width < 900 || bounds.height < 600) return false;
|
||||||
|
return screen.getAllDisplays().some(display => rectanglesOverlap(bounds, display.workArea));
|
||||||
|
}
|
||||||
|
|
||||||
|
function rectanglesOverlap(a, b) {
|
||||||
|
return a.x < b.x + b.width &&
|
||||||
|
a.x + a.width > b.x &&
|
||||||
|
a.y < b.y + b.height &&
|
||||||
|
a.y + a.height > b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveWindowState() {
|
||||||
|
if (!mainWindow) return;
|
||||||
|
const isFullScreen = mainWindow.isFullScreen();
|
||||||
|
const bounds = isFullScreen ? mainWindow.getNormalBounds() : mainWindow.getBounds();
|
||||||
|
updateConfig(cfg => {
|
||||||
|
cfg.windowState = { isFullScreen, bounds };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
createWindow();
|
createWindow();
|
||||||
registerAll(mainWindow);
|
registerAll(mainWindow);
|
||||||
|
|||||||
+5
-19
@@ -1,16 +1,8 @@
|
|||||||
const { ipcMain, dialog, app, shell } = require('electron');
|
const { ipcMain, dialog, shell } = require('electron');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
|
const { readConfig, updateConfig } = require('../config');
|
||||||
const configPath = path.join(app.getPath('userData'), 'config.json');
|
|
||||||
|
|
||||||
function readConfig() {
|
|
||||||
try { return JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch { return {}; }
|
|
||||||
}
|
|
||||||
function writeConfig(data) {
|
|
||||||
try { fs.writeFileSync(configPath, JSON.stringify(data, null, 2)); } catch {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function register(mainWindow) {
|
function register(mainWindow) {
|
||||||
ipcMain.handle('select-folder', async () => {
|
ipcMain.handle('select-folder', async () => {
|
||||||
@@ -33,9 +25,7 @@ function register(mainWindow) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('set-last-folder', (_e, folderPath) => {
|
ipcMain.handle('set-last-folder', (_e, folderPath) => {
|
||||||
const cfg = readConfig();
|
updateConfig(cfg => { cfg.lastFolder = folderPath; });
|
||||||
cfg.lastFolder = folderPath;
|
|
||||||
writeConfig(cfg);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('list-directories', (_e, folderPath) => {
|
ipcMain.handle('list-directories', (_e, folderPath) => {
|
||||||
@@ -64,9 +54,7 @@ function register(mainWindow) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('set-preview-on', (_e, on) => {
|
ipcMain.handle('set-preview-on', (_e, on) => {
|
||||||
const cfg = readConfig();
|
updateConfig(cfg => { cfg.previewOn = on; });
|
||||||
cfg.previewOn = on;
|
|
||||||
writeConfig(cfg);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('get-sidebar-width', () => {
|
ipcMain.handle('get-sidebar-width', () => {
|
||||||
@@ -75,9 +63,7 @@ function register(mainWindow) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('set-sidebar-width', (_e, width) => {
|
ipcMain.handle('set-sidebar-width', (_e, width) => {
|
||||||
const cfg = readConfig();
|
updateConfig(cfg => { cfg.sidebarWidth = width; });
|
||||||
cfg.sidebarWidth = width;
|
|
||||||
writeConfig(cfg);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user