2025-12-07 19:32:53 +02:00
|
|
|
import { useUIStore } from '@/stores/useUIStore';
|
|
|
|
|
import { updateDesktopSettings } from '@/lib/persistence';
|
|
|
|
|
import type { DesktopSettings } from '@/lib/desktop';
|
|
|
|
|
|
|
|
|
|
type AppearanceSlice = {
|
|
|
|
|
showReasoningTraces: boolean;
|
2026-02-24 03:28:30 +02:00
|
|
|
showDeletionDialog: boolean;
|
2026-01-26 00:24:40 +02:00
|
|
|
nativeNotificationsEnabled: boolean;
|
|
|
|
|
notificationMode: 'always' | 'hidden-only';
|
2026-01-30 20:15:00 +08:00
|
|
|
notifyOnSubtasks: boolean;
|
2026-02-08 17:58:29 -08:00
|
|
|
notifyOnCompletion: boolean;
|
|
|
|
|
notifyOnError: boolean;
|
|
|
|
|
notifyOnQuestion: boolean;
|
|
|
|
|
notificationTemplates: {
|
|
|
|
|
completion: { title: string; message: string };
|
|
|
|
|
error: { title: string; message: string };
|
|
|
|
|
question: { title: string; message: string };
|
|
|
|
|
subtask: { title: string; message: string };
|
|
|
|
|
};
|
|
|
|
|
summarizeLastMessage: boolean;
|
|
|
|
|
summaryThreshold: number;
|
|
|
|
|
summaryLength: number;
|
|
|
|
|
maxLastMessageLength: number;
|
2025-12-20 02:06:00 +02:00
|
|
|
autoDeleteEnabled: boolean;
|
|
|
|
|
autoDeleteAfterDays: number;
|
2026-01-26 00:24:40 +02:00
|
|
|
fontSize: number;
|
2026-02-04 16:32:25 +02:00
|
|
|
terminalFontSize: number;
|
2026-01-26 00:24:40 +02:00
|
|
|
padding: number;
|
|
|
|
|
cornerRadius: number;
|
|
|
|
|
inputBarOffset: number;
|
|
|
|
|
diffLayoutPreference: 'dynamic' | 'inline' | 'side-by-side';
|
|
|
|
|
diffViewMode: 'single' | 'stacked';
|
2025-12-07 19:32:53 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let initialized = false;
|
|
|
|
|
|
|
|
|
|
export const startAppearanceAutoSave = (): void => {
|
|
|
|
|
if (initialized || typeof window === 'undefined') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
|
|
|
|
|
|
let previous: AppearanceSlice = {
|
|
|
|
|
showReasoningTraces: useUIStore.getState().showReasoningTraces,
|
2026-02-24 03:28:30 +02:00
|
|
|
showDeletionDialog: useUIStore.getState().showDeletionDialog,
|
2026-01-26 00:24:40 +02:00
|
|
|
nativeNotificationsEnabled: useUIStore.getState().nativeNotificationsEnabled,
|
|
|
|
|
notificationMode: useUIStore.getState().notificationMode,
|
2026-01-30 20:15:00 +08:00
|
|
|
notifyOnSubtasks: useUIStore.getState().notifyOnSubtasks,
|
2026-02-08 17:58:29 -08:00
|
|
|
notifyOnCompletion: useUIStore.getState().notifyOnCompletion,
|
|
|
|
|
notifyOnError: useUIStore.getState().notifyOnError,
|
|
|
|
|
notifyOnQuestion: useUIStore.getState().notifyOnQuestion,
|
|
|
|
|
notificationTemplates: useUIStore.getState().notificationTemplates,
|
|
|
|
|
summarizeLastMessage: useUIStore.getState().summarizeLastMessage,
|
|
|
|
|
summaryThreshold: useUIStore.getState().summaryThreshold,
|
|
|
|
|
summaryLength: useUIStore.getState().summaryLength,
|
|
|
|
|
maxLastMessageLength: useUIStore.getState().maxLastMessageLength,
|
2025-12-20 02:06:00 +02:00
|
|
|
autoDeleteEnabled: useUIStore.getState().autoDeleteEnabled,
|
|
|
|
|
autoDeleteAfterDays: useUIStore.getState().autoDeleteAfterDays,
|
2026-01-26 00:24:40 +02:00
|
|
|
fontSize: useUIStore.getState().fontSize,
|
2026-02-04 16:32:25 +02:00
|
|
|
terminalFontSize: useUIStore.getState().terminalFontSize,
|
2026-01-26 00:24:40 +02:00
|
|
|
padding: useUIStore.getState().padding,
|
|
|
|
|
cornerRadius: useUIStore.getState().cornerRadius,
|
|
|
|
|
inputBarOffset: useUIStore.getState().inputBarOffset,
|
|
|
|
|
diffLayoutPreference: useUIStore.getState().diffLayoutPreference,
|
|
|
|
|
diffViewMode: useUIStore.getState().diffViewMode,
|
2025-12-07 19:32:53 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let pending: Partial<DesktopSettings> | null = null;
|
|
|
|
|
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
|
|
|
|
|
const flush = () => {
|
|
|
|
|
const payload = pending;
|
|
|
|
|
pending = null;
|
|
|
|
|
timer = null;
|
|
|
|
|
if (payload && Object.keys(payload).length > 0) {
|
|
|
|
|
void updateDesktopSettings(payload);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const schedule = (changes: Partial<DesktopSettings>) => {
|
|
|
|
|
pending = { ...(pending ?? {}), ...changes };
|
|
|
|
|
if (timer) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
timer = setTimeout(flush, 150);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useUIStore.subscribe((state) => {
|
|
|
|
|
const current: AppearanceSlice = {
|
|
|
|
|
showReasoningTraces: state.showReasoningTraces,
|
2026-02-24 03:28:30 +02:00
|
|
|
showDeletionDialog: state.showDeletionDialog,
|
2026-01-26 00:24:40 +02:00
|
|
|
nativeNotificationsEnabled: state.nativeNotificationsEnabled,
|
|
|
|
|
notificationMode: state.notificationMode,
|
2026-01-30 20:15:00 +08:00
|
|
|
notifyOnSubtasks: state.notifyOnSubtasks,
|
2026-02-08 17:58:29 -08:00
|
|
|
notifyOnCompletion: state.notifyOnCompletion,
|
|
|
|
|
notifyOnError: state.notifyOnError,
|
|
|
|
|
notifyOnQuestion: state.notifyOnQuestion,
|
|
|
|
|
notificationTemplates: state.notificationTemplates,
|
|
|
|
|
summarizeLastMessage: state.summarizeLastMessage,
|
|
|
|
|
summaryThreshold: state.summaryThreshold,
|
|
|
|
|
summaryLength: state.summaryLength,
|
|
|
|
|
maxLastMessageLength: state.maxLastMessageLength,
|
2025-12-20 02:06:00 +02:00
|
|
|
autoDeleteEnabled: state.autoDeleteEnabled,
|
|
|
|
|
autoDeleteAfterDays: state.autoDeleteAfterDays,
|
2026-01-26 00:24:40 +02:00
|
|
|
fontSize: state.fontSize,
|
2026-02-04 16:32:25 +02:00
|
|
|
terminalFontSize: state.terminalFontSize,
|
2026-01-26 00:24:40 +02:00
|
|
|
padding: state.padding,
|
|
|
|
|
cornerRadius: state.cornerRadius,
|
|
|
|
|
inputBarOffset: state.inputBarOffset,
|
|
|
|
|
diffLayoutPreference: state.diffLayoutPreference,
|
|
|
|
|
diffViewMode: state.diffViewMode,
|
2025-12-07 19:32:53 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const diff: Partial<DesktopSettings> = {};
|
|
|
|
|
|
|
|
|
|
if (current.showReasoningTraces !== previous.showReasoningTraces) {
|
|
|
|
|
diff.showReasoningTraces = current.showReasoningTraces;
|
|
|
|
|
}
|
2026-02-24 03:28:30 +02:00
|
|
|
if (current.showDeletionDialog !== previous.showDeletionDialog) {
|
|
|
|
|
diff.showDeletionDialog = current.showDeletionDialog;
|
|
|
|
|
}
|
2026-01-26 00:24:40 +02:00
|
|
|
if (current.nativeNotificationsEnabled !== previous.nativeNotificationsEnabled) {
|
|
|
|
|
diff.nativeNotificationsEnabled = current.nativeNotificationsEnabled;
|
|
|
|
|
}
|
|
|
|
|
if (current.notificationMode !== previous.notificationMode) {
|
|
|
|
|
diff.notificationMode = current.notificationMode;
|
|
|
|
|
}
|
2026-01-30 20:15:00 +08:00
|
|
|
if (current.notifyOnSubtasks !== previous.notifyOnSubtasks) {
|
|
|
|
|
diff.notifyOnSubtasks = current.notifyOnSubtasks;
|
|
|
|
|
}
|
2026-02-08 17:58:29 -08:00
|
|
|
if (current.notifyOnCompletion !== previous.notifyOnCompletion) {
|
|
|
|
|
diff.notifyOnCompletion = current.notifyOnCompletion;
|
|
|
|
|
}
|
|
|
|
|
if (current.notifyOnError !== previous.notifyOnError) {
|
|
|
|
|
diff.notifyOnError = current.notifyOnError;
|
|
|
|
|
}
|
|
|
|
|
if (current.notifyOnQuestion !== previous.notifyOnQuestion) {
|
|
|
|
|
diff.notifyOnQuestion = current.notifyOnQuestion;
|
|
|
|
|
}
|
|
|
|
|
if (JSON.stringify(current.notificationTemplates) !== JSON.stringify(previous.notificationTemplates)) {
|
|
|
|
|
diff.notificationTemplates = current.notificationTemplates;
|
|
|
|
|
}
|
|
|
|
|
if (current.summarizeLastMessage !== previous.summarizeLastMessage) {
|
|
|
|
|
diff.summarizeLastMessage = current.summarizeLastMessage;
|
|
|
|
|
}
|
|
|
|
|
if (current.summaryThreshold !== previous.summaryThreshold) {
|
|
|
|
|
diff.summaryThreshold = current.summaryThreshold;
|
|
|
|
|
}
|
|
|
|
|
if (current.summaryLength !== previous.summaryLength) {
|
|
|
|
|
diff.summaryLength = current.summaryLength;
|
|
|
|
|
}
|
|
|
|
|
if (current.maxLastMessageLength !== previous.maxLastMessageLength) {
|
|
|
|
|
diff.maxLastMessageLength = current.maxLastMessageLength;
|
|
|
|
|
}
|
2025-12-20 02:06:00 +02:00
|
|
|
if (current.autoDeleteEnabled !== previous.autoDeleteEnabled) {
|
|
|
|
|
diff.autoDeleteEnabled = current.autoDeleteEnabled;
|
|
|
|
|
}
|
|
|
|
|
if (current.autoDeleteAfterDays !== previous.autoDeleteAfterDays) {
|
|
|
|
|
diff.autoDeleteAfterDays = current.autoDeleteAfterDays;
|
|
|
|
|
}
|
2026-01-26 00:24:40 +02:00
|
|
|
if (current.fontSize !== previous.fontSize) {
|
|
|
|
|
diff.fontSize = current.fontSize;
|
|
|
|
|
}
|
2026-02-04 16:32:25 +02:00
|
|
|
if (current.terminalFontSize !== previous.terminalFontSize) {
|
|
|
|
|
diff.terminalFontSize = current.terminalFontSize;
|
|
|
|
|
}
|
2026-01-26 00:24:40 +02:00
|
|
|
if (current.padding !== previous.padding) {
|
|
|
|
|
diff.padding = current.padding;
|
|
|
|
|
}
|
|
|
|
|
if (current.cornerRadius !== previous.cornerRadius) {
|
|
|
|
|
diff.cornerRadius = current.cornerRadius;
|
|
|
|
|
}
|
|
|
|
|
if (current.inputBarOffset !== previous.inputBarOffset) {
|
|
|
|
|
diff.inputBarOffset = current.inputBarOffset;
|
|
|
|
|
}
|
|
|
|
|
if (current.diffLayoutPreference !== previous.diffLayoutPreference) {
|
|
|
|
|
diff.diffLayoutPreference = current.diffLayoutPreference;
|
|
|
|
|
}
|
|
|
|
|
if (current.diffViewMode !== previous.diffViewMode) {
|
|
|
|
|
diff.diffViewMode = current.diffViewMode;
|
|
|
|
|
}
|
2025-12-07 19:32:53 +02:00
|
|
|
|
|
|
|
|
previous = current;
|
|
|
|
|
|
|
|
|
|
if (Object.keys(diff).length > 0) {
|
|
|
|
|
schedule(diff);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|