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

101 lines
3.0 KiB
JavaScript

import { state } from './state.js';
import { setStatus, showToast } from './ui.js';
import { renderGrid, showEmptyGrid } from './grid.js';
import * as history from './history.js';
export function createHistoryController({
btnRename,
btnUndo,
btnRedo,
updateSortButtons,
}) {
let busy = false;
function updateButtons() {
btnUndo.disabled = !history.canUndo();
btnRedo.disabled = !history.canRedo();
}
async function performUndo() {
if (busy || !history.canUndo()) {
if (!history.canUndo()) showToast('더 이상 되돌릴 수 없습니다');
return;
}
busy = true;
try {
const { entry, targetFiles } = history.undo();
if (entry.type === 'delete') {
const { restored, errors } = await window.api.restoreStagedFiles(entry.deletedEntries);
if (errors.length) showToast('일부 파일 복원 실패: ' + errors[0]);
applySnapshot(targetFiles, new Set(restored));
if (restored.length) setStatus(`${restored.length}개 파일 복원됨`, true);
} else {
applySnapshot(targetFiles, entry.affectedPaths);
}
} finally {
busy = false;
}
}
async function performRedo() {
if (busy || !history.canRedo()) {
if (!history.canRedo()) showToast('마지막 작업 상태입니다');
return;
}
busy = true;
try {
const nextEntry = history.peekRedo();
if (nextEntry.type === 'delete') {
const pathsToRedo = nextEntry.deletedEntries.map(e => e.originalPath);
const { staged, errors } = await window.api.stageDeleteFiles(pathsToRedo);
if (errors.length) showToast('일부 파일 삭제 실패: ' + errors[0]);
updateDeleteStagingPaths(nextEntry, staged);
const { targetFiles } = history.redo();
applySnapshot(targetFiles, null);
if (staged.length) setStatus(`${staged.length}개 파일 삭제됨`, true);
} else {
const { entry, targetFiles } = history.redo();
applySnapshot(targetFiles, entry.affectedPaths);
}
} finally {
busy = false;
}
}
function applySnapshot(targetFiles, affectedPaths = null) {
state.files.length = 0;
state.files.push(...targetFiles);
state.selectedIdxs.clear();
if (affectedPaths && affectedPaths.size > 0) {
const pathToIdx = new Map(state.files.map((f, i) => [f.path, i]));
affectedPaths.forEach(p => {
const idx = pathToIdx.get(p);
if (idx !== undefined) state.selectedIdxs.add(idx);
});
}
state.sortMode = null;
updateSortButtons();
if (!state.files.length) {
showEmptyGrid();
btnRename.disabled = true;
} else {
renderGrid();
btnRename.disabled = false;
}
updateButtons();
}
return { performUndo, performRedo, updateButtons };
}
function updateDeleteStagingPaths(entry, staged) {
const stagedByPath = new Map(staged.map(s => [s.originalPath, s.stagingPath]));
entry.deletedEntries.forEach(e => {
if (stagedByPath.has(e.originalPath)) e.stagingPath = stagedByPath.get(e.originalPath);
});
}