Files
photo-renamer/src/renderer/renderer.js
T

154 lines
6.4 KiB
JavaScript

import { state } from './state.js';
import * as history from './history.js';
import {
updateSelCount, updateNumberBadges,
updateNewNameLabels, refreshCardSelection,
} from './grid.js';
import { doRename } from './rename.js';
import { handleFolderDrop } from './move.js';
import { initModalControls } from './modal.js';
import { buildSequentialName, getNameFormat } from './utils/file-names.js';
import { initKeyboardShortcuts } from './keyboard.js';
import { createFolderController } from './folder-controller.js';
import { createHistoryController } from './history-controller.js';
import * as deleteHandler from './delete.js';
import * as pinchZoom from './handlers/pinch-zoom.js';
import * as selection from './handlers/selection.js';
import * as dragDrop from './handlers/drag-drop.js';
import * as hoverPreview from './handlers/image-preview.js';
import * as fileExplorer from './handlers/file-explorer.js';
import * as sidebarResize from './handlers/sidebar-resize.js';
import { log } from './logger.js';
// ── DOM ──────────────────────────────────────────────
const btnOpen = document.getElementById('btn-open');
const btnSortName = document.getElementById('btn-sort-name');
const btnSortDate = document.getElementById('btn-sort-date');
const btnRename = document.getElementById('btn-rename');
const inputPrefix = document.getElementById('input-prefix');
const inputDigits = document.getElementById('input-digits');
const inputPostfix = document.getElementById('input-postfix');
const previewName = document.getElementById('preview-name');
const dirPath = document.getElementById('dir-path');
const rubberBand = document.getElementById('rubber-band');
const grid = document.getElementById('grid');
const gridContainer = document.getElementById('grid-container');
const dragGhostEl = document.getElementById('drag-ghost');
const thumbSizeHint = document.getElementById('thumb-size-hint');
const btnPreviewToggle = document.getElementById('btn-preview-toggle');
const btnUndo = document.getElementById('btn-undo');
const btnRedo = document.getElementById('btn-redo');
const fileExplorerContainer = document.querySelector('.file-explorer');
const aside = document.querySelector('aside');
const sidebarResizer = document.getElementById('sidebar-resizer');
const folderController = createFolderController({
btnRename,
btnSortName,
btnSortDate,
dirPath,
inputPrefix,
updatePreview,
});
const historyController = createHistoryController({
btnRename,
btnUndo,
btnRedo,
updateSortButtons: folderController.updateSortButtons,
});
// ── 핸들러 초기화 ─────────────────────────────────
history.setOnUpdate(historyController.updateButtons);
initModalControls();
const callbacks = {
refreshCardSelection, updateSelCount, updateNumberBadges, updateNewNameLabels,
pushHistory: (affectedPaths) => history.pushReorder(state.files, affectedPaths),
};
selection.init({ gridContainer, rubberBand, grid, state, callbacks });
dragDrop.init({ grid, gridContainer, dragGhostEl, state, callbacks, fileExplorerEl: fileExplorerContainer, onFolderDrop: handleFolderDrop });
hoverPreview.init();
deleteHandler.init(grid);
fileExplorer.init(fileExplorerContainer, folderController.loadFolder);
window.api.onFullscreenChange((isFullscreen) => {
document.body.classList.toggle('fullscreen', isFullscreen);
});
// ── 앱 시작 ───────────────────────────────────────
(async () => {
log('startup', 'init start');
const [lastFolder, homeDir, previewOn, sidebarWidth, thumbSize] = await Promise.all([
window.api.getLastFolder(),
window.api.getHomeDir(),
window.api.getPreviewOn(),
window.api.getSidebarWidth(),
window.api.getThumbSize(),
]);
log('startup', 'settings loaded', { lastFolder, homeDir, previewOn, sidebarWidth, thumbSize });
folderController.setHomeDir(homeDir);
btnPreviewToggle.classList.toggle('active', previewOn);
hoverPreview.setEnabled(previewOn);
sidebarResize.init({
aside,
handle: sidebarResizer,
initialWidth: sidebarWidth,
onResizeEnd: width => window.api.setSidebarWidth(width),
});
pinchZoom.init({
gridContainer,
thumbSizeHint,
initialSize: thumbSize,
onChange: size => window.api.setThumbSize(size),
});
const target = lastFolder || homeDir;
log('startup', 'initial folder target', { target, fromLastFolder: Boolean(lastFolder) });
await fileExplorer.loadTree(homeDir, target);
await folderController.loadFolder(target);
log('startup', 'init done');
})();
// ── 버튼 / 키보드 이벤트 ─────────────────────────
inputPrefix.addEventListener('input', updatePreview);
inputDigits.addEventListener('input', updatePreview);
inputPostfix.addEventListener('input', updatePreview);
btnOpen.addEventListener('click', () => {
log('ui', 'open button clicked');
folderController.openFolder();
});
btnSortName.addEventListener('click', () => folderController.sortFiles('name'));
btnSortDate.addEventListener('click', () => folderController.sortFiles('date'));
btnRename.addEventListener('click', doRename);
btnUndo.addEventListener('click', historyController.performUndo);
btnRedo.addEventListener('click', historyController.performRedo);
btnPreviewToggle.addEventListener('click', () => {
const on = btnPreviewToggle.classList.toggle('active');
hoverPreview.setEnabled(on);
window.api.setPreviewOn(on);
});
initKeyboardShortcuts({
btnOpen,
btnRename,
btnPreviewToggle,
deleteSelected: deleteHandler.deleteSelected,
performUndo: historyController.performUndo,
performRedo: historyController.performRedo,
refreshSelection: () => {
refreshCardSelection();
updateSelCount();
},
selectAll: () => state.files.forEach((_, i) => state.selectedIdxs.add(i)),
});
// ── 포맷 미리보기 ─────────────────────────────────
function updatePreview() {
const format = getNameFormat(inputPrefix, inputDigits, 3, inputPostfix);
const fileName = state.files[0]?.name || 'preview.jpg';
previewName.textContent = buildSequentialName(fileName, 0, format);
updateNewNameLabels();
}