refactor(settings): Update synchronization logic

This commit is contained in:
Will Miao
2025-09-15 10:30:06 +08:00
parent 9366d3d2d0
commit 2f7e44a76f
13 changed files with 72 additions and 102 deletions

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "Beispielbilder-Pfad erfolgreich aktualisiert", "pathUpdated": "Beispielbilder-Pfad erfolgreich aktualisiert",
"pathUpdateFailed": "Fehler beim Aktualisieren des Beispielbilder-Pfads: {message}",
"downloadInProgress": "Download bereits in Bearbeitung", "downloadInProgress": "Download bereits in Bearbeitung",
"enterLocationFirst": "Bitte geben Sie zuerst einen Download-Speicherort ein", "enterLocationFirst": "Bitte geben Sie zuerst einen Download-Speicherort ein",
"downloadStarted": "Beispielbilder-Download gestartet", "downloadStarted": "Beispielbilder-Download gestartet",

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "Example images path updated successfully", "pathUpdated": "Example images path updated successfully",
"pathUpdateFailed": "Failed to update example images path: {message}",
"downloadInProgress": "Download already in progress", "downloadInProgress": "Download already in progress",
"enterLocationFirst": "Please enter a download location first", "enterLocationFirst": "Please enter a download location first",
"downloadStarted": "Example images download started", "downloadStarted": "Example images download started",

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "Ruta de imágenes de ejemplo actualizada exitosamente", "pathUpdated": "Ruta de imágenes de ejemplo actualizada exitosamente",
"pathUpdateFailed": "Error al actualizar la ruta de imágenes de ejemplo: {message}",
"downloadInProgress": "Descarga ya en progreso", "downloadInProgress": "Descarga ya en progreso",
"enterLocationFirst": "Por favor introduce primero una ubicación de descarga", "enterLocationFirst": "Por favor introduce primero una ubicación de descarga",
"downloadStarted": "Descarga de imágenes de ejemplo iniciada", "downloadStarted": "Descarga de imágenes de ejemplo iniciada",

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "Chemin des images d'exemple mis à jour avec succès", "pathUpdated": "Chemin des images d'exemple mis à jour avec succès",
"pathUpdateFailed": "Échec de la mise à jour du chemin des images d'exemple : {message}",
"downloadInProgress": "Téléchargement déjà en cours", "downloadInProgress": "Téléchargement déjà en cours",
"enterLocationFirst": "Veuillez d'abord entrer un emplacement de téléchargement", "enterLocationFirst": "Veuillez d'abord entrer un emplacement de téléchargement",
"downloadStarted": "Téléchargement des images d'exemple démarré", "downloadStarted": "Téléchargement des images d'exemple démarré",

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "例画像パスが正常に更新されました", "pathUpdated": "例画像パスが正常に更新されました",
"pathUpdateFailed": "例画像パスの更新に失敗しました:{message}",
"downloadInProgress": "ダウンロードは既に進行中です", "downloadInProgress": "ダウンロードは既に進行中です",
"enterLocationFirst": "最初にダウンロード場所を入力してください", "enterLocationFirst": "最初にダウンロード場所を入力してください",
"downloadStarted": "例画像のダウンロードが開始されました", "downloadStarted": "例画像のダウンロードが開始されました",

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "예시 이미지 경로가 성공적으로 업데이트되었습니다", "pathUpdated": "예시 이미지 경로가 성공적으로 업데이트되었습니다",
"pathUpdateFailed": "예시 이미지 경로 업데이트 실패: {message}",
"downloadInProgress": "이미 다운로드가 진행 중입니다", "downloadInProgress": "이미 다운로드가 진행 중입니다",
"enterLocationFirst": "먼저 다운로드 위치를 입력해주세요", "enterLocationFirst": "먼저 다운로드 위치를 입력해주세요",
"downloadStarted": "예시 이미지 다운로드가 시작되었습니다", "downloadStarted": "예시 이미지 다운로드가 시작되었습니다",

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "Путь к примерам изображений успешно обновлен", "pathUpdated": "Путь к примерам изображений успешно обновлен",
"pathUpdateFailed": "Не удалось обновить путь к примерам изображений: {message}",
"downloadInProgress": "Загрузка уже в процессе", "downloadInProgress": "Загрузка уже в процессе",
"enterLocationFirst": "Пожалуйста, сначала введите место загрузки", "enterLocationFirst": "Пожалуйста, сначала введите место загрузки",
"downloadStarted": "Загрузка примеров изображений начата", "downloadStarted": "Загрузка примеров изображений начата",

View File

@@ -21,17 +21,17 @@
"disabled": "已禁用" "disabled": "已禁用"
}, },
"language": { "language": {
"select": "语言", "select": "Language",
"select_help": "选择你喜欢的界面语言", "select_help": "Choose your preferred language for the interface",
"english": "English", "english": "English",
"chinese_simplified": "中文(简体)", "chinese_simplified": "中文(简体)",
"chinese_traditional": "中文(繁体)", "chinese_traditional": "中文(繁体)",
"russian": "俄语", "russian": "Русский",
"german": "德语", "german": "Deutsch",
"japanese": "日", "japanese": "日本語",
"korean": "韩语", "korean": "한국어",
"french": "法语", "french": "Français",
"spanish": "西班牙语" "spanish": "Español"
}, },
"fileSize": { "fileSize": {
"zero": "0 字节", "zero": "0 字节",
@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "示例图片路径更新成功", "pathUpdated": "示例图片路径更新成功",
"pathUpdateFailed": "更新示例图片路径失败:{message}",
"downloadInProgress": "下载已在进行中", "downloadInProgress": "下载已在进行中",
"enterLocationFirst": "请先输入下载位置", "enterLocationFirst": "请先输入下载位置",
"downloadStarted": "示例图片下载已开始", "downloadStarted": "示例图片下载已开始",

View File

@@ -1166,6 +1166,7 @@
}, },
"exampleImages": { "exampleImages": {
"pathUpdated": "範例圖片路徑已更新", "pathUpdated": "範例圖片路徑已更新",
"pathUpdateFailed": "更新範例圖片路徑失敗:{message}",
"downloadInProgress": "下載已在進行中", "downloadInProgress": "下載已在進行中",
"enterLocationFirst": "請先輸入下載位置", "enterLocationFirst": "請先輸入下載位置",
"downloadStarted": "範例圖片下載已開始", "downloadStarted": "範例圖片下載已開始",

View File

@@ -139,7 +139,10 @@ class MiscRoutes:
'proxy_host', 'proxy_host',
'proxy_port', 'proxy_port',
'proxy_username', 'proxy_username',
'proxy_password' 'proxy_password',
'example_images_path',
'optimizeExampleImages',
'autoDownloadExampleImages'
] ]
# Build response with only the keys that should be synced # Build response with only the keys that should be synced

View File

@@ -7,7 +7,7 @@ import { HeaderManager } from './components/Header.js';
import { settingsManager } from './managers/SettingsManager.js'; import { settingsManager } from './managers/SettingsManager.js';
import { moveManager } from './managers/MoveManager.js'; import { moveManager } from './managers/MoveManager.js';
import { bulkManager } from './managers/BulkManager.js'; import { bulkManager } from './managers/BulkManager.js';
import { exampleImagesManager } from './managers/ExampleImagesManager.js'; import { ExampleImagesManager } from './managers/ExampleImagesManager.js';
import { helpManager } from './managers/HelpManager.js'; import { helpManager } from './managers/HelpManager.js';
import { bannerService } from './managers/BannerService.js'; import { bannerService } from './managers/BannerService.js';
import { initTheme, initBackToTop } from './utils/uiHelpers.js'; import { initTheme, initBackToTop } from './utils/uiHelpers.js';
@@ -50,7 +50,7 @@ export class AppCore {
bannerService.initialize(); bannerService.initialize();
window.modalManager = modalManager; window.modalManager = modalManager;
window.settingsManager = settingsManager; window.settingsManager = settingsManager;
window.exampleImagesManager = exampleImagesManager; window.exampleImagesManager = new ExampleImagesManager();
window.helpManager = helpManager; window.helpManager = helpManager;
window.moveManager = moveManager; window.moveManager = moveManager;
window.bulkManager = bulkManager; window.bulkManager = bulkManager;

View File

@@ -1,9 +1,10 @@
import { showToast } from '../utils/uiHelpers.js'; import { showToast } from '../utils/uiHelpers.js';
import { state } from '../state/index.js'; import { state } from '../state/index.js';
import { getStorageItem, setStorageItem } from '../utils/storageHelpers.js'; import { getStorageItem, setStorageItem } from '../utils/storageHelpers.js';
import { settingsManager } from './SettingsManager.js';
// ExampleImagesManager.js // ExampleImagesManager.js
class ExampleImagesManager { export class ExampleImagesManager {
constructor() { constructor() {
this.isDownloading = false; this.isDownloading = false;
this.isPaused = false; this.isPaused = false;
@@ -27,7 +28,12 @@ class ExampleImagesManager {
} }
// Initialize the manager // Initialize the manager
initialize() { async initialize() {
// Wait for settings to be initialized before proceeding
if (window.settingsManager) {
await window.settingsManager.waitForInitialization();
}
// Initialize event listeners // Initialize event listeners
this.initEventListeners(); this.initEventListeners();
@@ -78,86 +84,41 @@ class ExampleImagesManager {
// Get custom path input element // Get custom path input element
const pathInput = document.getElementById('exampleImagesPath'); const pathInput = document.getElementById('exampleImagesPath');
// Set path from storage if available // Set path from backend settings
const savedPath = getStorageItem('example_images_path', ''); const savedPath = state.global.settings.example_images_path || '';
if (savedPath) { if (pathInput) {
pathInput.value = savedPath; pathInput.value = savedPath;
// Enable download button if path is set // Enable download button if path is set
this.updateDownloadButtonState(true); this.updateDownloadButtonState(!!savedPath);
// Sync the saved path with the backend
try {
const response = await fetch('/api/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
example_images_path: savedPath
})
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
if (!data.success) {
console.error('Failed to sync example images path with backend:', data.error);
}
} catch (error) {
console.error('Failed to sync saved path with backend:', error);
}
} else {
// Disable download button if no path is set
this.updateDownloadButtonState(false);
} }
// Add event listener to validate path input // Add event listener to validate path input
pathInput.addEventListener('input', async () => { if (pathInput) {
const hasPath = pathInput.value.trim() !== ''; pathInput.addEventListener('input', async () => {
this.updateDownloadButtonState(hasPath); const hasPath = pathInput.value.trim() !== '';
this.updateDownloadButtonState(hasPath);
// Save path to storage when changed // Update path in backend settings using settingsManager
if (hasPath) {
setStorageItem('example_images_path', pathInput.value);
// Update path in backend settings
try { try {
const response = await fetch('/api/settings', { await settingsManager.saveSetting('example_images_path', pathInput.value);
method: 'POST', if (hasPath) {
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
example_images_path: pathInput.value
})
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
if (!data.success) {
console.error('Failed to update example images path in backend:', data.error);
} else {
showToast('toast.exampleImages.pathUpdated', {}, 'success'); showToast('toast.exampleImages.pathUpdated', {}, 'success');
} }
} catch (error) { } catch (error) {
console.error('Failed to update example images path:', error); console.error('Failed to update example images path:', error);
showToast('toast.exampleImages.pathUpdateFailed', { message: error.message }, 'error');
} }
}
// Setup or clear auto download based on path availability // Setup or clear auto download based on path availability
if (state.global.settings.autoDownloadExampleImages) { if (state.global.settings.autoDownloadExampleImages) {
if (hasPath) { if (hasPath) {
this.setupAutoDownload(); this.setupAutoDownload();
} else { } else {
this.clearAutoDownload(); this.clearAutoDownload();
}
} }
} });
}); }
} catch (error) { } catch (error) {
console.error('Failed to initialize path options:', error); console.error('Failed to initialize path options:', error);
} }
@@ -255,7 +216,7 @@ class ExampleImagesManager {
return; return;
} }
const optimize = document.getElementById('optimizeExampleImages').checked; const optimize = state.global.settings.optimizeExampleImages;
const response = await fetch('/api/download-example-images', { const response = await fetch('/api/download-example-images', {
method: 'POST', method: 'POST',
@@ -746,7 +707,7 @@ class ExampleImagesManager {
console.log('Performing auto download check...'); console.log('Performing auto download check...');
const outputDir = document.getElementById('exampleImagesPath').value; const outputDir = document.getElementById('exampleImagesPath').value;
const optimize = document.getElementById('optimizeExampleImages').checked; const optimize = state.global.settings.optimizeExampleImages;
const response = await fetch('/api/download-example-images', { const response = await fetch('/api/download-example-images', {
method: 'POST', method: 'POST',
@@ -771,6 +732,3 @@ class ExampleImagesManager {
} }
} }
} }
// Create singleton instance
export const exampleImagesManager = new ExampleImagesManager();

View File

@@ -47,8 +47,6 @@ export class SettingsManager {
'autoplayOnHover', 'autoplayOnHover',
'displayDensity', 'displayDensity',
'cardInfoDisplay', 'cardInfoDisplay',
'optimizeExampleImages',
'autoDownloadExampleImages',
'includeTriggerWords' 'includeTriggerWords'
]; ];
@@ -76,14 +74,6 @@ export class SettingsManager {
state.global.settings.autoplayOnHover = false; state.global.settings.autoplayOnHover = false;
} }
if (state.global.settings.optimizeExampleImages === undefined) {
state.global.settings.optimizeExampleImages = true;
}
if (state.global.settings.autoDownloadExampleImages === undefined) {
state.global.settings.autoDownloadExampleImages = true;
}
if (state.global.settings.cardInfoDisplay === undefined) { if (state.global.settings.cardInfoDisplay === undefined) {
state.global.settings.cardInfoDisplay = 'always'; state.global.settings.cardInfoDisplay = 'always';
} }
@@ -147,7 +137,10 @@ export class SettingsManager {
proxy_host: '', proxy_host: '',
proxy_port: '', proxy_port: '',
proxy_username: '', proxy_username: '',
proxy_password: '' proxy_password: '',
example_images_path: '',
optimizeExampleImages: true,
autoDownloadExampleImages: true
}; };
Object.keys(backendDefaults).forEach(key => { Object.keys(backendDefaults).forEach(key => {
@@ -172,8 +165,6 @@ export class SettingsManager {
'autoplayOnHover', 'autoplayOnHover',
'displayDensity', 'displayDensity',
'cardInfoDisplay', 'cardInfoDisplay',
'optimizeExampleImages',
'autoDownloadExampleImages',
'includeTriggerWords' 'includeTriggerWords'
]; ];
@@ -203,7 +194,10 @@ export class SettingsManager {
'proxy_host', 'proxy_host',
'proxy_port', 'proxy_port',
'proxy_username', 'proxy_username',
'proxy_password' 'proxy_password',
'example_images_path',
'optimizeExampleImages',
'autoDownloadExampleImages'
]; ];
return backendKeys.includes(settingKey); return backendKeys.includes(settingKey);
} }
@@ -230,6 +224,12 @@ export class SettingsManager {
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to save setting to backend'); throw new Error('Failed to save setting to backend');
} }
// Parse response and check for success
const data = await response.json();
if (data.success === false) {
throw new Error(data.error || 'Failed to save setting to backend');
}
} catch (error) { } catch (error) {
console.error(`Failed to save backend setting ${settingKey}:`, error); console.error(`Failed to save backend setting ${settingKey}:`, error);
throw error; throw error;
@@ -985,8 +985,6 @@ export class SettingsManager {
await this.saveSetting(settingKey, value); await this.saveSetting(settingKey, value);
} }
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
// Apply frontend settings immediately // Apply frontend settings immediately
this.applyFrontendSettings(); this.applyFrontendSettings();
@@ -999,8 +997,10 @@ export class SettingsManager {
if (value === 'compact') densityName = "Compact"; if (value === 'compact') densityName = "Compact";
showToast('toast.settings.displayDensitySet', { density: densityName }, 'success'); showToast('toast.settings.displayDensitySet', { density: densityName }, 'success');
return;
} }
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
} catch (error) { } catch (error) {
showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error'); showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error');
} }