mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 01:45:54 +08:00
feat: app-store 适配 PathEntry — 新增 togglePath、loadPaths 合并禁用状态、savePaths 过滤 disabled
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+73
-21
@@ -3,16 +3,17 @@ import { invoke } from '@tauri-apps/api/core';
|
|||||||
import i18n from '@/i18n';
|
import i18n from '@/i18n';
|
||||||
import { UndoRedoManager, OperationType, TargetType } from '@/core/undo-redo';
|
import { UndoRedoManager, OperationType, TargetType } from '@/core/undo-redo';
|
||||||
import { pathClean } from '@/core/path-manager';
|
import { pathClean } from '@/core/path-manager';
|
||||||
|
import type { PathEntry } from '@/core/path-entry';
|
||||||
import appConfig from '@/config/default.json';
|
import appConfig from '@/config/default.json';
|
||||||
|
|
||||||
export type TabId = 'system' | 'user' | 'merged';
|
export type TabId = 'system' | 'user' | 'merged';
|
||||||
|
|
||||||
interface AppState {
|
interface AppState {
|
||||||
sysPaths: string[];
|
sysPaths: PathEntry[];
|
||||||
userPaths: string[];
|
userPaths: PathEntry[];
|
||||||
undoRedo: UndoRedoManager;
|
undoRedo: UndoRedoManager;
|
||||||
_savedSys: string[]; // 上次保存时的快照,用于 isModified 判断
|
_savedSys: PathEntry[]; // 上次保存时的快照,用于 isModified 判断
|
||||||
_savedUser: string[];
|
_savedUser: PathEntry[];
|
||||||
|
|
||||||
activeTab: TabId;
|
activeTab: TabId;
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
@@ -37,6 +38,8 @@ interface AppState {
|
|||||||
replacePaths: (target: TargetType, newPaths: string[]) => void;
|
replacePaths: (target: TargetType, newPaths: string[]) => void;
|
||||||
clearPaths: (target: TargetType) => void;
|
clearPaths: (target: TargetType) => void;
|
||||||
|
|
||||||
|
togglePath: (index: number, target: TargetType) => void;
|
||||||
|
|
||||||
undo: () => void;
|
undo: () => void;
|
||||||
redo: () => void;
|
redo: () => void;
|
||||||
|
|
||||||
@@ -46,8 +49,8 @@ interface AppState {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function arraysEqual(a: readonly string[], b: readonly string[]): boolean {
|
function arraysEqual(a: readonly PathEntry[], b: readonly PathEntry[]): boolean {
|
||||||
return a.length === b.length && a.every((v, i) => v === b[i]);
|
return a.length === b.length && a.every((v, i) => v.path === b[i].path && v.enabled === b[i].enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAppStore = create<AppState>((set, get) => {
|
export const useAppStore = create<AppState>((set, get) => {
|
||||||
@@ -80,10 +83,11 @@ export const useAppStore = create<AppState>((set, get) => {
|
|||||||
addPath: (path, target) => {
|
addPath: (path, target) => {
|
||||||
const state = get();
|
const state = get();
|
||||||
const list = target === TargetType.SYSTEM ? state.sysPaths : state.userPaths;
|
const list = target === TargetType.SYSTEM ? state.sysPaths : state.userPaths;
|
||||||
const newList = [...list, path];
|
const entry: PathEntry = { path, enabled: true };
|
||||||
|
const newList = [...list, entry];
|
||||||
state.undoRedo.push({
|
state.undoRedo.push({
|
||||||
type: OperationType.ADD, target, index: newList.length - 1, count: 1,
|
type: OperationType.ADD, target, index: newList.length - 1, count: 1,
|
||||||
oldPaths: [], newPaths: [path],
|
oldPaths: [], newPaths: [entry],
|
||||||
});
|
});
|
||||||
if (target === TargetType.SYSTEM) set({ sysPaths: newList });
|
if (target === TargetType.SYSTEM) set({ sysPaths: newList });
|
||||||
else set({ userPaths: newList });
|
else set({ userPaths: newList });
|
||||||
@@ -93,14 +97,15 @@ export const useAppStore = create<AppState>((set, get) => {
|
|||||||
editPath: (index, newPath, target) => {
|
editPath: (index, newPath, target) => {
|
||||||
const state = get();
|
const state = get();
|
||||||
const list = target === TargetType.SYSTEM ? state.sysPaths : state.userPaths;
|
const list = target === TargetType.SYSTEM ? state.sysPaths : state.userPaths;
|
||||||
const oldPath = list[index];
|
const oldEntry = list[index];
|
||||||
if (oldPath === undefined) return;
|
if (!oldEntry) return;
|
||||||
|
const newEntry: PathEntry = { path: newPath, enabled: oldEntry.enabled };
|
||||||
state.undoRedo.push({
|
state.undoRedo.push({
|
||||||
type: OperationType.EDIT, target, index, count: 1,
|
type: OperationType.EDIT, target, index, count: 1,
|
||||||
oldPaths: [oldPath], newPaths: [newPath],
|
oldPaths: [oldEntry], newPaths: [newEntry],
|
||||||
});
|
});
|
||||||
const newList = [...list];
|
const newList = [...list];
|
||||||
newList[index] = newPath;
|
newList[index] = newEntry;
|
||||||
if (target === TargetType.SYSTEM) set({ sysPaths: newList });
|
if (target === TargetType.SYSTEM) set({ sysPaths: newList });
|
||||||
else set({ userPaths: newList });
|
else set({ userPaths: newList });
|
||||||
markDirty();
|
markDirty();
|
||||||
@@ -171,21 +176,22 @@ export const useAppStore = create<AppState>((set, get) => {
|
|||||||
markDirty();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
return removed;
|
return removed.map(e => e.path);
|
||||||
},
|
},
|
||||||
|
|
||||||
replacePaths: (target, newPaths) => {
|
replacePaths: (target, newPaths) => {
|
||||||
if (newPaths.length === 0) return;
|
if (newPaths.length === 0) return;
|
||||||
const state = get();
|
const state = get();
|
||||||
const list = target === TargetType.SYSTEM ? state.sysPaths : state.userPaths;
|
const list = target === TargetType.SYSTEM ? state.sysPaths : state.userPaths;
|
||||||
|
const entries: PathEntry[] = newPaths.map(p => ({ path: p, enabled: true }));
|
||||||
|
|
||||||
state.undoRedo.push({
|
state.undoRedo.push({
|
||||||
type: OperationType.IMPORT, target, index: 0, count: newPaths.length,
|
type: OperationType.IMPORT, target, index: 0, count: entries.length,
|
||||||
oldPaths: [...list], newPaths: [...newPaths],
|
oldPaths: [...list], newPaths: [...entries],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (target === TargetType.SYSTEM) set({ sysPaths: [...newPaths], selectedIndices: [] });
|
if (target === TargetType.SYSTEM) set({ sysPaths: [...entries], selectedIndices: [] });
|
||||||
else set({ userPaths: [...newPaths], selectedIndices: [] });
|
else set({ userPaths: [...entries], selectedIndices: [] });
|
||||||
markDirty();
|
markDirty();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -204,6 +210,32 @@ export const useAppStore = create<AppState>((set, get) => {
|
|||||||
markDirty();
|
markDirty();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
togglePath: (index, target) => {
|
||||||
|
const state = get();
|
||||||
|
const list = target === TargetType.SYSTEM ? state.sysPaths : state.userPaths;
|
||||||
|
const oldEntry = list[index];
|
||||||
|
if (!oldEntry) return;
|
||||||
|
const newEntry: PathEntry = { path: oldEntry.path, enabled: !oldEntry.enabled };
|
||||||
|
|
||||||
|
state.undoRedo.push({
|
||||||
|
type: OperationType.TOGGLE, target, index, count: 1,
|
||||||
|
oldPaths: [oldEntry], newPaths: [newEntry],
|
||||||
|
});
|
||||||
|
|
||||||
|
const newList = [...list];
|
||||||
|
newList[index] = newEntry;
|
||||||
|
if (target === TargetType.SYSTEM) set({ sysPaths: newList });
|
||||||
|
else set({ userPaths: newList });
|
||||||
|
markDirty();
|
||||||
|
|
||||||
|
// 即时保存禁用状态
|
||||||
|
const { sysPaths: sys, userPaths: usr } = get();
|
||||||
|
const sysDisabled = sys.filter(e => !e.enabled).map(e => e.path);
|
||||||
|
const usrDisabled = usr.filter(e => !e.enabled).map(e => e.path);
|
||||||
|
invoke('save_disabled_state', { system: sysDisabled, user: usrDisabled })
|
||||||
|
.catch(() => {});
|
||||||
|
},
|
||||||
|
|
||||||
undo: () => {
|
undo: () => {
|
||||||
const { undoRedo, sysPaths, userPaths, _savedSys, _savedUser } = get();
|
const { undoRedo, sysPaths, userPaths, _savedSys, _savedUser } = get();
|
||||||
const result = undoRedo.undo(sysPaths, userPaths);
|
const result = undoRedo.undo(sysPaths, userPaths);
|
||||||
@@ -235,9 +267,27 @@ export const useAppStore = create<AppState>((set, get) => {
|
|||||||
invoke<string[]>('load_system_paths'),
|
invoke<string[]>('load_system_paths'),
|
||||||
invoke<string[]>('load_user_paths'),
|
invoke<string[]>('load_user_paths'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 加载禁用状态(文件不存在时返回空)
|
||||||
|
let sysDisabled: string[] = [];
|
||||||
|
let usrDisabled: string[] = [];
|
||||||
|
try {
|
||||||
|
const result = await invoke<[string[], string[]]>('load_disabled_state');
|
||||||
|
sysDisabled = result[0];
|
||||||
|
usrDisabled = result[1];
|
||||||
|
} catch {
|
||||||
|
// 文件不存在或损坏,忽略
|
||||||
|
}
|
||||||
|
|
||||||
|
const sysSet = new Set(sysDisabled);
|
||||||
|
const usrSet = new Set(usrDisabled);
|
||||||
|
|
||||||
|
const sysEntries: PathEntry[] = sysArr.map(p => ({ path: p, enabled: !sysSet.has(p) }));
|
||||||
|
const usrEntries: PathEntry[] = userArr.map(p => ({ path: p, enabled: !usrSet.has(p) }));
|
||||||
|
|
||||||
set({
|
set({
|
||||||
sysPaths: sysArr, userPaths: userArr,
|
sysPaths: sysEntries, userPaths: usrEntries,
|
||||||
_savedSys: [...sysArr], _savedUser: [...userArr],
|
_savedSys: [...sysEntries], _savedUser: [...usrEntries],
|
||||||
undoRedo: new UndoRedoManager(appConfig.undo.maxHistory),
|
undoRedo: new UndoRedoManager(appConfig.undo.maxHistory),
|
||||||
isLoading: false, isModified: false,
|
isLoading: false, isModified: false,
|
||||||
statusMessage: i18n.t('status.loaded', { sysCount: sysArr.length, userCount: userArr.length }),
|
statusMessage: i18n.t('status.loaded', { sysCount: sysArr.length, userCount: userArr.length }),
|
||||||
@@ -252,7 +302,9 @@ export const useAppStore = create<AppState>((set, get) => {
|
|||||||
if (state.isSaving) return;
|
if (state.isSaving) return;
|
||||||
set({ isSaving: true, statusMessage: i18n.t('status.saving') });
|
set({ isSaving: true, statusMessage: i18n.t('status.saving') });
|
||||||
|
|
||||||
const { sysPaths, userPaths } = state;
|
// 只保存 enabled 的路径到注册表
|
||||||
|
const sysPaths = state.sysPaths.filter(e => e.enabled).map(e => e.path);
|
||||||
|
const userPaths = state.userPaths.filter(e => e.enabled).map(e => e.path);
|
||||||
const sysJoined = sysPaths.join(';');
|
const sysJoined = sysPaths.join(';');
|
||||||
const userJoined = userPaths.join(';');
|
const userJoined = userPaths.join(';');
|
||||||
|
|
||||||
@@ -275,7 +327,7 @@ export const useAppStore = create<AppState>((set, get) => {
|
|||||||
|
|
||||||
if (sysOk && userOk) {
|
if (sysOk && userOk) {
|
||||||
invoke('broadcast_env_change').catch(() => {});
|
invoke('broadcast_env_change').catch(() => {});
|
||||||
const savedSys = [...sysPaths], savedUser = [...userPaths];
|
const savedSys = [...state.sysPaths], savedUser = [...state.userPaths];
|
||||||
set({ isModified: false, isSaving: false, statusMessage: i18n.t('status.saved'), _savedSys: savedSys, _savedUser: savedUser });
|
set({ isModified: false, isSaving: false, statusMessage: i18n.t('status.saved'), _savedSys: savedSys, _savedUser: savedUser });
|
||||||
} else {
|
} else {
|
||||||
const reason = (!sysOk && sysResult.status === 'rejected') ? String(sysResult.reason) :
|
const reason = (!sysOk && sysResult.status === 'rejected') ? String(sysResult.reason) :
|
||||||
|
|||||||
Reference in New Issue
Block a user