mirror of
https://github.com/maigamo/Daily-Task-Auto-Generator.git
synced 2026-07-22 05:48:30 +00:00
728 lines
No EOL
29 KiB
TypeScript
728 lines
No EOL
29 KiB
TypeScript
import { App, ButtonComponent, DropdownComponent, Notice, Plugin, PluginSettingTab, Setting, TextAreaComponent, TextComponent, ToggleComponent } from 'obsidian';
|
||
import { AutoGenerateMode, DEFAULT_SETTINGS, DEFAULT_TEMPLATE_EN, DEFAULT_TEMPLATE_ZH, DailyTaskSettings, Language } from '../models/settings';
|
||
import { getTranslation, setCurrentLanguage } from '../i18n/i18n';
|
||
import { renderTemplate } from '../utils/templateEngine';
|
||
import { TaskGenerator } from '../taskGenerator';
|
||
import { setTextContentByLines, createIconButton, createTextElement } from '../utils/domUtils';
|
||
// 导入主插件类型定义
|
||
import DailyTaskPlugin from '../main';
|
||
|
||
// CSS 相关常量(class名称)
|
||
const SettingsSectionCSS = "daily-task-settings-section";
|
||
const ButtonCSS = "daily-task-button";
|
||
const PreviewButtonCSS = "daily-task-preview-button";
|
||
const ResetButtonCSS = "daily-task-reset-button";
|
||
const EditorCSS = "daily-task-editor";
|
||
const VerticalStackCSS = "daily-task-vertical-stack";
|
||
const TextRightCSS = "daily-task-text-right";
|
||
const TextCenterCSS = "daily-task-text-center";
|
||
const ScrollbarSlimCSS = "daily-task-slim-scrollbar";
|
||
const SaveIndicatorCSS = "daily-task-save-indicator";
|
||
const SuccessIconCSS = "daily-task-success-icon";
|
||
const SettingTopSpaceCSS = "daily-task-setting-top-space";
|
||
const InputContainerCSS = "daily-task-input-container";
|
||
const InputCSS = "daily-task-input";
|
||
|
||
/**
|
||
* 添加插件自定义样式
|
||
* 注意:样式内容现在已移至外部CSS文件
|
||
*/
|
||
function addCustomStyles() {
|
||
// 样式已移至src/styles.css,无需在此处添加内联样式
|
||
// 插件加载时会自动加载styles.css文件
|
||
}
|
||
|
||
/**
|
||
* 插件设置标签页
|
||
*/
|
||
export class DailyTaskSettingTab extends PluginSettingTab {
|
||
plugin: Plugin;
|
||
settingsManager: SettingsManager;
|
||
taskGenerator: TaskGenerator;
|
||
previewEl: HTMLElement | null = null;
|
||
addTaskButton: ButtonComponent | null = null;
|
||
|
||
// 目录输入框
|
||
rootDirInput: TextComponent | null = null;
|
||
|
||
// 标记设置是否已修改但未保存
|
||
dirtySettings: boolean = false;
|
||
|
||
// 自动保存目录的方法
|
||
autoSaveRootDir: (value: string) => Promise<void>;
|
||
|
||
constructor(app: App, plugin: Plugin) {
|
||
super(app, plugin);
|
||
this.plugin = plugin;
|
||
|
||
// 获取父插件中的设置管理器引用 - 使用类型断言为DailyTaskPlugin而不是any
|
||
this.settingsManager = (plugin as DailyTaskPlugin).settingsManager;
|
||
|
||
// 创建任务生成器
|
||
this.taskGenerator = new TaskGenerator(app, this.settingsManager);
|
||
}
|
||
|
||
display(): void {
|
||
const { containerEl } = this;
|
||
containerEl.empty();
|
||
containerEl.classList.add('daily-task-setting-tab');
|
||
|
||
const settings = this.settingsManager.getSettings();
|
||
|
||
// 添加顶部间距(增加间距以改善界面美观)
|
||
const topSpacing = document.createElement('div');
|
||
topSpacing.classList.add(SettingTopSpaceCSS);
|
||
containerEl.appendChild(topSpacing);
|
||
|
||
// 根目录设置
|
||
const rootDirSetting = new Setting(containerEl)
|
||
.setName(getTranslation('settings.rootDir'))
|
||
.setDesc(getTranslation('settings.rootDir.desc'));
|
||
|
||
// 创建输入框容器,使其可以包含额外元素
|
||
const inputContainer = document.createElement('div');
|
||
inputContainer.classList.add(InputContainerCSS);
|
||
rootDirSetting.controlEl.appendChild(inputContainer);
|
||
|
||
this.rootDirInput = new TextComponent(inputContainer)
|
||
.setValue(settings.rootDir)
|
||
.onChange(async (value) => {
|
||
if (value.trim() !== '') {
|
||
// 设置已更改,准备自动保存
|
||
this.dirtySettings = true;
|
||
|
||
// 启动自动保存定时器
|
||
this.autoSaveRootDir(value);
|
||
}
|
||
});
|
||
|
||
// 给input元素设置类和placeholder属性
|
||
if (this.rootDirInput && this.rootDirInput.inputEl) {
|
||
this.rootDirInput.inputEl.classList.add(InputCSS);
|
||
this.rootDirInput.inputEl.placeholder = 'DailyTasks';
|
||
}
|
||
|
||
// 添加自动保存指示器
|
||
const saveIndicator = document.createElement('div');
|
||
saveIndicator.classList.add(SaveIndicatorCSS);
|
||
inputContainer.appendChild(saveIndicator);
|
||
|
||
// 创建保存成功图标
|
||
const saveSuccessIcon = document.createElement('span');
|
||
saveSuccessIcon.classList.add('svg-icon', 'lucide-check', SuccessIconCSS);
|
||
saveIndicator.appendChild(saveSuccessIcon);
|
||
|
||
// 记录自动保存定时器
|
||
let autoSaveTimer: number | null = null;
|
||
|
||
// 自动保存方法
|
||
this.autoSaveRootDir = async (value: string) => {
|
||
// 清除之前的定时器
|
||
if (autoSaveTimer !== null) {
|
||
window.clearTimeout(autoSaveTimer);
|
||
}
|
||
|
||
// 设置新的定时器,延迟800ms保存(在用户停止输入后)
|
||
autoSaveTimer = window.setTimeout(async () => {
|
||
let pathToSave = value.trim();
|
||
if (pathToSave === '') {
|
||
pathToSave = 'DailyTasks'; // 默认存放目录
|
||
}
|
||
|
||
// 实际保存设置
|
||
await this.settingsManager.updateSettings({ rootDir: pathToSave });
|
||
this.dirtySettings = false;
|
||
|
||
// 显示保存成功的视觉反馈
|
||
saveIndicator.classList.add('save-indicator-visible');
|
||
saveIndicator.classList.remove('save-indicator-hidden');
|
||
window.setTimeout(() => {
|
||
saveIndicator.classList.remove('save-indicator-visible');
|
||
saveIndicator.classList.add('save-indicator-hidden');
|
||
}, 1500);
|
||
|
||
}, 800);
|
||
};
|
||
|
||
// 自动生成模式
|
||
const autoGenSetting = new Setting(containerEl)
|
||
.setName(getTranslation('settings.autoGenerate'))
|
||
.setDesc(getTranslation('settings.autoGenerate.desc'));
|
||
|
||
// 自定义三选滑块
|
||
const toggleContainer = document.createElement('div');
|
||
toggleContainer.classList.add('mode-toggle-container');
|
||
autoGenSetting.controlEl.appendChild(toggleContainer);
|
||
|
||
const modes = [
|
||
{ value: AutoGenerateMode.NONE, label: getTranslation('settings.mode.none') },
|
||
{ value: AutoGenerateMode.DAILY, label: getTranslation('settings.mode.daily') },
|
||
{ value: AutoGenerateMode.WORKDAY, label: getTranslation('settings.mode.workday') }
|
||
];
|
||
|
||
// 滑块指示器
|
||
const slider = document.createElement('div');
|
||
slider.classList.add('mode-toggle-slider');
|
||
toggleContainer.appendChild(slider);
|
||
|
||
// 更新滑块位置
|
||
const updateSlider = (index: number) => {
|
||
// 移除之前的位置类
|
||
slider.classList.remove('slider-position-0', 'slider-position-1', 'slider-position-2');
|
||
// 添加新的位置类
|
||
slider.classList.add(`slider-position-${index}`);
|
||
};
|
||
|
||
// 设置默认模式为仅工作日生成(WorkDay)
|
||
let currentModeIndex = modes.findIndex(mode => mode.value === settings.autoGenerateMode);
|
||
if (currentModeIndex === -1) {
|
||
// 如果没有找到有效的模式,设置为工作日模式
|
||
currentModeIndex = modes.findIndex(mode => mode.value === AutoGenerateMode.WORKDAY);
|
||
// 更新设置到工作日模式
|
||
this.settingsManager.updateSettings({ autoGenerateMode: AutoGenerateMode.WORKDAY });
|
||
}
|
||
updateSlider(currentModeIndex);
|
||
|
||
// 创建选项
|
||
modes.forEach((mode, index) => {
|
||
const option = document.createElement('div');
|
||
option.classList.add('mode-toggle-option');
|
||
option.textContent = mode.label;
|
||
|
||
if (mode.value === settings.autoGenerateMode) {
|
||
option.classList.add('active');
|
||
}
|
||
|
||
option.addEventListener('click', async () => {
|
||
// 更新视觉状态
|
||
toggleContainer.querySelectorAll('.mode-toggle-option').forEach(el => {
|
||
el.classList.remove('active');
|
||
});
|
||
option.classList.add('active');
|
||
|
||
// 更新滑块位置
|
||
updateSlider(index);
|
||
|
||
// 保存设置
|
||
await this.settingsManager.updateSettings({ autoGenerateMode: mode.value });
|
||
});
|
||
|
||
toggleContainer.appendChild(option);
|
||
});
|
||
|
||
// 语言设置
|
||
// TODO: 应该使用Obsidian API的app.i18n.locale获取系统语言设置
|
||
// 需要在manifest.json中设置minAppVersion: "1.8.0"或更高
|
||
// 可以移除此设置并修改SettingsManager.getCurrentLanguage()方法
|
||
new Setting(containerEl)
|
||
.setName(getTranslation('settings.language'))
|
||
.setDesc(getTranslation('settings.language.desc'))
|
||
.addDropdown(dropdown => {
|
||
dropdown
|
||
.addOption(Language.AUTO, getTranslation('settings.language.auto'))
|
||
.addOption(Language.ZH, getTranslation('settings.language.zh'))
|
||
.addOption(Language.EN, getTranslation('settings.language.en'))
|
||
.setValue(settings.language)
|
||
.onChange(async (value) => {
|
||
await this.settingsManager.updateSettings({ language: value as Language });
|
||
// 需要重新加载设置页面以更新翻译
|
||
this.display();
|
||
});
|
||
});
|
||
|
||
// 通知显示时间
|
||
new Setting(containerEl)
|
||
.setName(getTranslation('settings.notificationDuration'))
|
||
.setDesc(getTranslation('settings.notificationDuration.desc'))
|
||
.addText(text => {
|
||
const component = text
|
||
.setValue(settings.successNotificationDuration.toString())
|
||
.onChange(async (value) => {
|
||
const duration = parseInt(value);
|
||
if (!isNaN(duration) && duration > 0) {
|
||
await this.settingsManager.updateSettings({ successNotificationDuration: duration });
|
||
}
|
||
});
|
||
|
||
// 直接设置placeholder属性
|
||
component.inputEl.placeholder = '3000';
|
||
|
||
return component;
|
||
});
|
||
|
||
// 任务统计功能开关
|
||
new Setting(containerEl)
|
||
.setName(getTranslation('settings.taskStatistics'))
|
||
.setDesc(getTranslation('settings.taskStatistics.desc'))
|
||
.addToggle((toggle) => {
|
||
// 设置开关样式
|
||
const toggleEl = toggle
|
||
.setValue(settings.taskStatistics)
|
||
.onChange(async (value) => {
|
||
await this.settingsManager.updateSettings({ taskStatistics: value });
|
||
});
|
||
|
||
// 自定义开关样式 - 使用DOM元素访问
|
||
// @ts-ignore - 添加这行来忽略TypeScript警告
|
||
const toggleControl = toggle.toggleEl || toggle.containerEl.querySelector('.checkbox-container');
|
||
if (toggleControl) {
|
||
toggleControl.classList.add('task-statistics-toggle');
|
||
|
||
// 添加图标 - 使用DOM父元素访问
|
||
const toggleContainer = toggleControl.parentElement;
|
||
if (toggleContainer) {
|
||
const iconEl = document.createElement('span');
|
||
iconEl.classList.add('svg-icon', 'lucide-bar-chart-2');
|
||
toggleContainer.prepend(iconEl);
|
||
}
|
||
}
|
||
|
||
return toggleEl;
|
||
});
|
||
|
||
// 模板设置 - 使用常规方式创建标题
|
||
// TODO: 如果Obsidian API支持,应该使用Setting.setHeading()方法创建标题
|
||
// 例如: new Setting(containerEl).setName(getTranslation('settings.template')).setHeading();
|
||
containerEl.createEl('h3', { text: getTranslation('settings.template') });
|
||
|
||
// 添加模板使用逻辑说明
|
||
const templateDescription = document.createElement('p');
|
||
templateDescription.classList.add('template-description');
|
||
templateDescription.textContent = this.settingsManager.getCurrentLanguage() === 'zh' ?
|
||
'注意:默认模板会根据当前语言环境自动选择对应语言的内容。如果您自定义模板,将在所有语言环境中使用您的自定义内容。' :
|
||
'Note: Default template automatically adapts to your language environment. If you customize the template, your content will be used in all language environments.';
|
||
containerEl.appendChild(templateDescription);
|
||
|
||
// 添加模板变量说明
|
||
const templateVariablesEl = document.createElement('div');
|
||
templateVariablesEl.classList.add('template-variables');
|
||
|
||
// 创建变量内容
|
||
const variablesContent = this.settingsManager.getCurrentLanguage() === 'zh' ?
|
||
'<strong>可用变量:</strong> {{date}} - 日期, {{dateWithIcon}} - 带图标的日期, {{weekday}} - 星期几, {{yearProgress}} - 年进度, {{monthProgress}} - 月进度, {{time}} - 当前时间' :
|
||
'<strong>Available variables:</strong> {{date}} - Date, {{dateWithIcon}} - Date with icon, {{weekday}} - Day of week, {{yearProgress}} - Year progress, {{monthProgress}} - Month progress, {{time}} - Current time';
|
||
|
||
// 使用DOMParser安全地解析HTML内容
|
||
const parser = new DOMParser();
|
||
const doc = parser.parseFromString(variablesContent, 'text/html');
|
||
|
||
// 安全地添加解析后的内容
|
||
Array.from(doc.body.childNodes).forEach(node => {
|
||
templateVariablesEl.appendChild(document.importNode(node, true));
|
||
});
|
||
|
||
containerEl.appendChild(templateVariablesEl);
|
||
|
||
// 单一模板设置
|
||
const templateSetting = new Setting(containerEl)
|
||
.setName(getTranslation('settings.template'))
|
||
.setClass('template-setting');
|
||
|
||
const templateContainer = document.createElement('div');
|
||
templateContainer.classList.add('template-container', 'full-width-container');
|
||
|
||
// 获取当前模板内容
|
||
const currentTemplate = this.settingsManager.hasCustomTemplate() ?
|
||
this.settingsManager.getSettings().customTemplate :
|
||
this.settingsManager.getTemplateByLanguage();
|
||
|
||
const textarea = new TextAreaComponent(templateContainer)
|
||
.setValue(currentTemplate)
|
||
.setPlaceholder(this.settingsManager.getCurrentLanguage() === 'zh' ?
|
||
'在此处输入任务模板...' :
|
||
'Enter task template here...')
|
||
.onChange(async (value) => {
|
||
// 更新为自定义模板
|
||
await this.settingsManager.updateSettings({
|
||
customTemplate: value,
|
||
hasCustomTemplate: true
|
||
});
|
||
this.updatePreview(this.previewEl, value);
|
||
});
|
||
|
||
// 添加样式类
|
||
textarea.inputEl.classList.add('template-editor');
|
||
|
||
// 预览标题,使用flex布局居中
|
||
const previewHeader = document.createElement('div');
|
||
previewHeader.classList.add('template-preview-header');
|
||
|
||
// 预览按钮容器 - 左侧
|
||
const previewBtnContainer = document.createElement('div');
|
||
previewBtnContainer.classList.add('button-container');
|
||
|
||
// 重置按钮容器 - 右侧
|
||
const resetBtnContainer = document.createElement('div');
|
||
resetBtnContainer.classList.add('button-container');
|
||
|
||
// 预览按钮 - 改进样式
|
||
const toggleButton = new ButtonComponent(previewBtnContainer)
|
||
.setButtonText(getTranslation('settings.template.preview'));
|
||
|
||
// 添加样式类
|
||
toggleButton.buttonEl.addClass(TextCenterCSS);
|
||
toggleButton.buttonEl.addClass('daily-task-button-common');
|
||
toggleButton.buttonEl.addClass('daily-task-button-md');
|
||
|
||
// 手动添加眼睛图标
|
||
const eyeIcon = document.createElement('span');
|
||
eyeIcon.classList.add('svg-icon', 'lucide-eye');
|
||
toggleButton.buttonEl.prepend(eyeIcon);
|
||
|
||
// 预览区域
|
||
this.previewEl = document.createElement('div');
|
||
this.previewEl.classList.add('template-preview');
|
||
this.updatePreview(this.previewEl, currentTemplate);
|
||
templateContainer.appendChild(this.previewEl);
|
||
|
||
toggleButton.onClick(() => {
|
||
this.togglePreview(this.previewEl);
|
||
// 切换图标和按钮文本
|
||
if (this.previewEl && this.previewEl.classList.contains('visible')) {
|
||
eyeIcon.className = 'svg-icon lucide-eye-off';
|
||
toggleButton.setButtonText(getTranslation('settings.template.hide'));
|
||
toggleButton.buttonEl.classList.add('success-button');
|
||
} else {
|
||
eyeIcon.className = 'svg-icon lucide-eye';
|
||
toggleButton.setButtonText(getTranslation('settings.template.preview'));
|
||
toggleButton.buttonEl.classList.remove('success-button');
|
||
}
|
||
});
|
||
|
||
// 重置按钮 - 改进样式
|
||
const resetBtn = new ButtonComponent(resetBtnContainer)
|
||
.setButtonText(getTranslation('settings.resetDefault'));
|
||
|
||
// 添加样式类
|
||
resetBtn.buttonEl.addClass(TextCenterCSS);
|
||
resetBtn.buttonEl.addClass('daily-task-button-common');
|
||
resetBtn.buttonEl.addClass('daily-task-button-lg');
|
||
|
||
// 添加重置图标
|
||
const resetIcon = document.createElement('span');
|
||
resetIcon.classList.add('svg-icon', 'lucide-refresh-cw');
|
||
resetBtn.buttonEl.prepend(resetIcon);
|
||
|
||
// 添加重置事件
|
||
resetBtn.onClick(async () => {
|
||
// 将自定义模板设置为空,回到使用默认模板
|
||
await this.settingsManager.updateSettings({
|
||
customTemplate: '',
|
||
hasCustomTemplate: false
|
||
});
|
||
|
||
// 获取当前语言的默认模板
|
||
const defaultTemplate = this.settingsManager.getTemplateByLanguage();
|
||
|
||
// 更新输入框和预览
|
||
textarea.setValue(defaultTemplate);
|
||
this.updatePreview(this.previewEl, defaultTemplate);
|
||
|
||
// 显示成功提示动画
|
||
resetBtn.buttonEl.classList.add('success-button');
|
||
window.setTimeout(() => {
|
||
resetBtn.buttonEl.classList.remove('success-button');
|
||
}, 1000);
|
||
});
|
||
|
||
// 将按钮添加到各自的容器
|
||
previewHeader.appendChild(previewBtnContainer);
|
||
previewHeader.appendChild(resetBtnContainer);
|
||
templateContainer.appendChild(previewHeader);
|
||
|
||
templateSetting.controlEl.appendChild(templateContainer);
|
||
|
||
// 恢复默认设置 - 创建容器让按钮右对齐
|
||
const resetContainer = document.createElement('div');
|
||
resetContainer.classList.add('button-container');
|
||
containerEl.appendChild(resetContainer);
|
||
|
||
// 恢复默认设置按钮
|
||
const resetDefaultBtn = new ButtonComponent(resetContainer)
|
||
.setButtonText(getTranslation('settings.resetToDefault'));
|
||
|
||
// 添加样式类
|
||
resetDefaultBtn.buttonEl.addClass(TextCenterCSS);
|
||
resetDefaultBtn.buttonEl.addClass('danger-button');
|
||
resetDefaultBtn.buttonEl.addClass('daily-task-button-common');
|
||
resetDefaultBtn.buttonEl.addClass('daily-task-button-lg');
|
||
|
||
// 添加重置图标
|
||
const resetIcon2 = document.createElement('span');
|
||
resetIcon2.classList.add('svg-icon', 'lucide-refresh-cw');
|
||
resetDefaultBtn.buttonEl.prepend(resetIcon2);
|
||
|
||
// 为全局重置按钮添加事件处理
|
||
resetDefaultBtn.onClick(async () => {
|
||
await this.settingsManager.resetToDefaults();
|
||
this.display();
|
||
});
|
||
|
||
// 手动添加今日任务按钮 - 右对齐显示
|
||
const addTaskContainer = document.createElement('div');
|
||
addTaskContainer.classList.add('button-container');
|
||
containerEl.appendChild(addTaskContainer);
|
||
|
||
this.addTaskButton = new ButtonComponent(addTaskContainer)
|
||
.setButtonText(getTranslation('settings.addTaskButton'))
|
||
.setCta();
|
||
|
||
// 添加样式类 - 确保按钮文字居中
|
||
if (this.addTaskButton && this.addTaskButton.buttonEl) {
|
||
this.addTaskButton.buttonEl.addClass(TextCenterCSS);
|
||
this.addTaskButton.buttonEl.addClass('daily-task-button-common');
|
||
}
|
||
|
||
// 手动添加任务按钮事件处理
|
||
this.addTaskButton.onClick(async () => {
|
||
// 检查目录设置
|
||
const rootDir = this.settingsManager.getSettings().rootDir;
|
||
|
||
// 添加loading状态
|
||
if (this.addTaskButton && this.addTaskButton.buttonEl) {
|
||
this.addTaskButton.buttonEl.classList.add('loading');
|
||
}
|
||
this.addTaskButton?.setDisabled(true);
|
||
|
||
try {
|
||
// 添加任务
|
||
await this.taskGenerator.addTaskManually();
|
||
} catch (e) {
|
||
new Notice(`添加任务失败: ${e.message || e}`);
|
||
} finally {
|
||
// 移除loading状态
|
||
window.setTimeout(() => {
|
||
if (this.addTaskButton && this.addTaskButton.buttonEl) {
|
||
this.addTaskButton.buttonEl.classList.remove('loading');
|
||
}
|
||
this.addTaskButton?.setDisabled(false);
|
||
}, 500);
|
||
}
|
||
});
|
||
|
||
// 添加图标
|
||
const calendarIcon = document.createElement('span');
|
||
calendarIcon.classList.add('svg-icon', 'lucide-calendar-plus');
|
||
this.addTaskButton.buttonEl.prepend(calendarIcon);
|
||
}
|
||
|
||
/**
|
||
* 更新模板预览
|
||
*/
|
||
private updatePreview(previewEl: HTMLElement | null, template: string): void {
|
||
if (!previewEl) return;
|
||
|
||
const renderedContent = renderTemplate(template);
|
||
|
||
// 使用domUtils中的工具函数安全地设置内容
|
||
setTextContentByLines(previewEl, renderedContent);
|
||
}
|
||
|
||
/**
|
||
* 切换预览的显示/隐藏
|
||
*/
|
||
private togglePreview(previewEl: HTMLElement | null): void {
|
||
if (!previewEl) return;
|
||
|
||
if (previewEl.classList.contains('hidden-element')) {
|
||
previewEl.classList.remove('hidden-element');
|
||
previewEl.classList.add('visible-element', 'visible');
|
||
} else {
|
||
previewEl.classList.add('hidden-element');
|
||
previewEl.classList.remove('visible-element', 'visible');
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置管理器
|
||
* 负责加载、保存和提供设置访问接口
|
||
*/
|
||
export class SettingsManager {
|
||
private plugin: Plugin;
|
||
private settings: DailyTaskSettings;
|
||
|
||
constructor(plugin: Plugin) {
|
||
this.plugin = plugin;
|
||
this.settings = Object.assign({}, DEFAULT_SETTINGS);
|
||
}
|
||
|
||
/**
|
||
* 获取当前设置
|
||
*/
|
||
getSettings(): DailyTaskSettings {
|
||
return this.settings;
|
||
}
|
||
|
||
/**
|
||
* 更新设置并保存
|
||
* @param settings 要更新的设置
|
||
*/
|
||
async updateSettings(settings: Partial<DailyTaskSettings>): Promise<void> {
|
||
this.settings = {
|
||
...this.settings,
|
||
...settings
|
||
};
|
||
await this.saveSettings();
|
||
|
||
// 更新当前语言
|
||
this.updateCurrentLanguage();
|
||
}
|
||
|
||
/**
|
||
* 保存设置到数据存储
|
||
*/
|
||
async saveSettings(): Promise<void> {
|
||
await (this.plugin as DailyTaskPlugin).saveData(this.settings);
|
||
}
|
||
|
||
/**
|
||
* 加载设置
|
||
*/
|
||
async loadSettings(): Promise<void> {
|
||
const loadedData = await (this.plugin as DailyTaskPlugin).loadData();
|
||
if (loadedData) {
|
||
// 合并默认设置和已保存的设置
|
||
this.settings = {
|
||
...DEFAULT_SETTINGS,
|
||
...loadedData
|
||
};
|
||
|
||
// 确保在升级插件后,新增的设置项也有默认值
|
||
this.ensureSettingsCompleteness();
|
||
} else {
|
||
// 如果没有加载到数据,使用默认设置但将自动生成模式改为工作日
|
||
this.settings = {
|
||
...DEFAULT_SETTINGS,
|
||
autoGenerateMode: AutoGenerateMode.WORKDAY
|
||
};
|
||
}
|
||
|
||
// 更新当前语言
|
||
this.updateCurrentLanguage();
|
||
}
|
||
|
||
/**
|
||
* 确保设置完整性,为新增的设置项提供默认值
|
||
*/
|
||
private ensureSettingsCompleteness(): void {
|
||
const defaultKeys = Object.keys(DEFAULT_SETTINGS);
|
||
defaultKeys.forEach(key => {
|
||
// 如果当前设置中缺少某个默认设置项,添加默认值
|
||
if (!(key in this.settings)) {
|
||
// 先将对象转换为unknown,再转换为Record<string, unknown>
|
||
((this.settings as unknown) as Record<string, unknown>)[key] =
|
||
((DEFAULT_SETTINGS as unknown) as Record<string, unknown>)[key];
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 恢复默认设置
|
||
*/
|
||
async resetToDefaults(): Promise<void> {
|
||
this.settings = Object.assign({}, DEFAULT_SETTINGS);
|
||
await this.saveSettings();
|
||
|
||
// 更新当前语言
|
||
this.updateCurrentLanguage();
|
||
}
|
||
|
||
/**
|
||
* 根据语言获取当前使用的模板
|
||
* 如果当前模板不是默认模板,则不再区分语言
|
||
*/
|
||
getCurrentTemplate(): string {
|
||
const language = this.getCurrentLanguage();
|
||
|
||
// 中文环境
|
||
if (language === 'zh') {
|
||
// 如果中文模板已被修改(不等于默认模板),使用中文模板
|
||
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
|
||
return this.settings.templateZh;
|
||
}
|
||
// 如果英文模板已被修改,使用英文模板
|
||
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
|
||
return this.settings.templateEn;
|
||
}
|
||
// 如果都是默认模板,使用中文默认模板
|
||
return this.settings.templateZh;
|
||
}
|
||
// 英文环境
|
||
else {
|
||
// 如果英文模板已被修改(不等于默认模板),使用英文模板
|
||
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
|
||
return this.settings.templateEn;
|
||
}
|
||
// 如果中文模板已被修改,使用中文模板
|
||
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
|
||
return this.settings.templateZh;
|
||
}
|
||
// 如果都是默认模板,使用英文默认模板
|
||
return this.settings.templateEn;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取当前语言设置
|
||
*/
|
||
getCurrentLanguage(): string {
|
||
// TODO: 应该使用Obsidian API的app.i18n.locale获取系统语言设置
|
||
// 例如:return this.plugin.app.i18n.locale.startsWith('zh') ? 'zh' : 'en';
|
||
if (this.settings.language === Language.AUTO) {
|
||
// 自动检测系统语言
|
||
const systemLanguage = window.navigator.language.toLowerCase();
|
||
return systemLanguage.startsWith('zh') ? 'zh' : 'en';
|
||
}
|
||
return this.settings.language;
|
||
}
|
||
|
||
/**
|
||
* 更新当前语言
|
||
*/
|
||
private updateCurrentLanguage(): void {
|
||
const language = this.getCurrentLanguage();
|
||
setCurrentLanguage(language);
|
||
}
|
||
|
||
/**
|
||
* 获取当前语言的模板
|
||
*/
|
||
getTemplateByLanguage(): string {
|
||
const language = this.getCurrentLanguage();
|
||
|
||
// 中文环境
|
||
if (language === 'zh') {
|
||
// 如果中文模板已被修改(不等于默认模板),使用中文模板
|
||
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
|
||
return this.settings.templateZh;
|
||
}
|
||
// 如果英文模板已被修改,使用英文模板
|
||
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
|
||
return this.settings.templateEn;
|
||
}
|
||
// 如果都是默认模板,使用中文默认模板
|
||
return this.settings.templateZh;
|
||
}
|
||
// 英文环境
|
||
else {
|
||
// 如果英文模板已被修改(不等于默认模板),使用英文模板
|
||
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
|
||
return this.settings.templateEn;
|
||
}
|
||
// 如果中文模板已被修改,使用中文模板
|
||
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
|
||
return this.settings.templateZh;
|
||
}
|
||
// 如果都是默认模板,使用英文默认模板
|
||
return this.settings.templateEn;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查是否存在自定义模板
|
||
*/
|
||
hasCustomTemplate(): boolean {
|
||
return !!this.settings.customTemplate;
|
||
}
|
||
}
|