feat: Complete Preferences system implementation
- PreferencesService: QSettings-based persistence for all app settings - StartupBehaviorService: Windows registry auto-start management with policy detection - TranslationService: Language management with QTranslator, 9 built-in languages - AiActionOptionsService: 30+ AI translation language options - SettingsView: New 'Preferences' tab with full UI: * Search Mode (Local/Online) * Default App Mode (Mail/Calendar/Contacts/Settings) * Language selector (9 built-in + .qm files) * Email Sync Interval (1-1440 minutes) * Startup Behavior (auto-start, minimize to tray, notifications) * AI Translation (default language, summarize language, summary save path) - MainMainWindow: Service wiring (PreferencesService, StartupBehaviorService, TranslationService, AiActionOptionsService) - CMake: Added all new service files All services integrated and wired to SettingsView.
This commit is contained in:
+203
-3
@@ -1,6 +1,8 @@
|
||||
#include "settingsview.h"
|
||||
#include "services/accountservice.h"
|
||||
#include "core/models/account.h"
|
||||
#include "services/preferencesservice.h"
|
||||
#include "services/startupbehaviorservice.h"
|
||||
#include "services/translationservice.h"
|
||||
#include "services/aiactionoptionsservice.h"
|
||||
#include "db/dao/common_structs.h"
|
||||
#include "db/dao/categorydao.h"
|
||||
#include "db/dao/ruledao.h"
|
||||
@@ -34,6 +36,8 @@
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlDatabase>
|
||||
#include <QHeaderView>
|
||||
#include <QSpinBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
SettingsView::SettingsView(QWidget *parent) : QWidget(parent) {
|
||||
setupUI();
|
||||
@@ -45,6 +49,7 @@ void SettingsView::setupUI() {
|
||||
|
||||
m_tabWidget = new QTabWidget();
|
||||
m_tabWidget->addTab(createAccountsTab(), tr("Accounts"));
|
||||
m_tabWidget->addTab(createPreferencesTab(), tr("Preferences"));
|
||||
m_tabWidget->addTab(createCategoriesTab(), tr("Categories"));
|
||||
m_tabWidget->addTab(createRulesTab(), tr("Rules"));
|
||||
m_tabWidget->addTab(createTemplatesTab(), tr("Templates"));
|
||||
@@ -452,7 +457,202 @@ QWidget* SettingsView::createAppearanceTab() {
|
||||
return widget;
|
||||
}
|
||||
|
||||
// ========== Slots for Accounts ==========
|
||||
QWidget* SettingsView::createPreferencesTab() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(20, 20, 20, 20);
|
||||
layout->setSpacing(16);
|
||||
|
||||
QLabel *title = new QLabel(tr("Preferences"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
// Search Mode
|
||||
QGroupBox *searchGroup = new QGroupBox(tr("Search"));
|
||||
QFormLayout *searchLayout = new QFormLayout(searchGroup);
|
||||
|
||||
m_searchModeCombo = new QComboBox();
|
||||
m_searchModeCombo->addItem(tr("Local"), QVariant(static_cast<int>(SearchMode::Local)));
|
||||
m_searchModeCombo->addItem(tr("Online"), QVariant(static_cast<int>(SearchMode::Online)));
|
||||
if (m_preferencesService) {
|
||||
m_searchModeCombo->setCurrentIndex(static_cast<int>(m_preferencesService->defaultSearchMode()));
|
||||
}
|
||||
connect(m_searchModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setDefaultSearchMode(static_cast<SearchMode>(m_searchModeCombo->itemData(index).toInt()));
|
||||
}
|
||||
});
|
||||
searchLayout->addRow(tr("Default search mode:"), m_searchModeCombo);
|
||||
layout->addWidget(searchGroup);
|
||||
|
||||
// Default App Mode
|
||||
QGroupBox *appModeGroup = new QGroupBox(tr("Default Application Mode"));
|
||||
QFormLayout *appModeLayout = new QFormLayout(appModeGroup);
|
||||
|
||||
m_defaultAppModeCombo = new QComboBox();
|
||||
m_defaultAppModeCombo->addItem(tr("Mail"), QVariant(static_cast<int>(WinoApplicationMode::Mail)));
|
||||
m_defaultAppModeCombo->addItem(tr("Calendar"), QVariant(static_cast<int>(WinoApplicationMode::Calendar)));
|
||||
m_defaultAppModeCombo->addItem(tr("Contacts"), QVariant(static_cast<int>(WinoApplicationMode::Contacts)));
|
||||
m_defaultAppModeCombo->addItem(tr("Settings"), QVariant(static_cast<int>(WinoApplicationMode::Settings)));
|
||||
if (m_preferencesService) {
|
||||
m_defaultAppModeCombo->setCurrentIndex(static_cast<int>(m_preferencesService->defaultApplicationMode()));
|
||||
}
|
||||
connect(m_defaultAppModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setDefaultApplicationMode(static_cast<WinoApplicationMode>(m_defaultAppModeCombo->itemData(index).toInt()));
|
||||
}
|
||||
});
|
||||
appModeLayout->addRow(tr("Default mode on startup:"), m_defaultAppModeCombo);
|
||||
layout->addWidget(appModeGroup);
|
||||
|
||||
// Language
|
||||
QGroupBox *languageGroup = new QGroupBox(tr("Language"));
|
||||
QFormLayout *languageLayout = new QFormLayout(languageGroup);
|
||||
|
||||
m_languageCombo = new QComboBox();
|
||||
if (m_translationService) {
|
||||
QVector<AppLanguageModel> languages = m_translationService->getAvailableLanguages();
|
||||
for (const AppLanguageModel &lang : languages) {
|
||||
m_languageCombo->addItem(lang.displayName, lang.language);
|
||||
}
|
||||
int idx = m_languageCombo->findData(m_translationService->currentLanguage());
|
||||
if (idx >= 0) m_languageCombo->setCurrentIndex(idx);
|
||||
}
|
||||
connect(m_languageCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
if (m_translationService) {
|
||||
m_translationService->setLanguage(m_languageCombo->itemData(index).toString());
|
||||
}
|
||||
});
|
||||
languageLayout->addRow(tr("Interface language:"), m_languageCombo);
|
||||
layout->addWidget(languageGroup);
|
||||
|
||||
// Email Sync Interval
|
||||
QGroupBox *syncGroup = new QGroupBox(tr("Email Synchronization"));
|
||||
QFormLayout *syncLayout = new QFormLayout(syncGroup);
|
||||
|
||||
m_syncIntervalSpin = new QSpinBox();
|
||||
m_syncIntervalSpin->setRange(1, 1440); // 1 minute to 24 hours
|
||||
m_syncIntervalSpin->setSuffix(tr(" minutes"));
|
||||
if (m_preferencesService) {
|
||||
m_syncIntervalSpin->setValue(m_preferencesService->emailSyncIntervalMinutes());
|
||||
}
|
||||
connect(m_syncIntervalSpin, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setEmailSyncIntervalMinutes(value);
|
||||
}
|
||||
});
|
||||
syncLayout->addRow(tr("Sync interval:"), m_syncIntervalSpin);
|
||||
layout->addWidget(syncGroup);
|
||||
|
||||
// Startup Behavior
|
||||
QGroupBox *startupGroup = new QGroupBox(tr("Startup"));
|
||||
QFormLayout *startupLayout = new QFormLayout(startupGroup);
|
||||
|
||||
m_startOnLoginCheck = new QCheckBox(tr("Start application on login"));
|
||||
if (m_preferencesService) {
|
||||
m_startOnLoginCheck->setChecked(m_preferencesService->startOnLogin());
|
||||
}
|
||||
connect(m_startOnLoginCheck, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setStartOnLogin(checked);
|
||||
}
|
||||
if (m_startupBehaviorService) {
|
||||
m_startupBehaviorService->toggleStartupBehavior(checked);
|
||||
}
|
||||
});
|
||||
startupLayout->addRow(m_startOnLoginCheck);
|
||||
|
||||
m_minimizeToTrayCheck = new QCheckBox(tr("Minimize to tray on close"));
|
||||
if (m_preferencesService) {
|
||||
m_minimizeToTrayCheck->setChecked(m_preferencesService->minimizeToTray());
|
||||
}
|
||||
connect(m_minimizeToTrayCheck, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setMinimizeToTray(checked);
|
||||
}
|
||||
});
|
||||
startupLayout->addRow(m_minimizeToTrayCheck);
|
||||
|
||||
m_enableNotificationsCheck = new QCheckBox(tr("Enable notifications"));
|
||||
if (m_preferencesService) {
|
||||
m_enableNotificationsCheck->setChecked(m_preferencesService->enableNotifications());
|
||||
}
|
||||
connect(m_enableNotificationsCheck, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setEnableNotifications(checked);
|
||||
}
|
||||
});
|
||||
startupLayout->addRow(m_enableNotificationsCheck);
|
||||
layout->addWidget(startupGroup);
|
||||
|
||||
// AI Translation
|
||||
QGroupBox *aiGroup = new QGroupBox(tr("AI Translation"));
|
||||
QFormLayout *aiLayout = new QFormLayout(aiGroup);
|
||||
|
||||
m_translateLanguageCombo = new QComboBox();
|
||||
if (m_aiActionOptionsService) {
|
||||
QVector<AiTranslateLanguageOption> options = m_aiActionOptionsService->getTranslateLanguageOptions();
|
||||
for (const AiTranslateLanguageOption &opt : options) {
|
||||
m_translateLanguageCombo->addItem(opt.displayName, opt.code);
|
||||
}
|
||||
if (m_preferencesService) {
|
||||
int idx = m_translateLanguageCombo->findData(m_preferencesService->aiDefaultTranslationLanguageCode());
|
||||
if (idx >= 0) m_translateLanguageCombo->setCurrentIndex(idx);
|
||||
}
|
||||
}
|
||||
connect(m_translateLanguageCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setAiDefaultTranslationLanguageCode(m_translateLanguageCombo->itemData(index).toString());
|
||||
}
|
||||
});
|
||||
aiLayout->addRow(tr("Default translation language:"), m_translateLanguageCombo);
|
||||
|
||||
m_summarizeLanguageCombo = new QComboBox();
|
||||
if (m_aiActionOptionsService) {
|
||||
QVector<AiTranslateLanguageOption> options = m_aiActionOptionsService->getTranslateLanguageOptions();
|
||||
for (const AiTranslateLanguageOption &opt : options) {
|
||||
m_summarizeLanguageCombo->addItem(opt.displayName, opt.code);
|
||||
}
|
||||
if (m_preferencesService) {
|
||||
int idx = m_summarizeLanguageCombo->findData(m_preferencesService->aiSummarizeLanguageCode());
|
||||
if (idx >= 0) m_summarizeLanguageCombo->setCurrentIndex(idx);
|
||||
}
|
||||
}
|
||||
connect(m_summarizeLanguageCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setAiSummarizeLanguageCode(m_summarizeLanguageCombo->itemData(index).toString());
|
||||
}
|
||||
});
|
||||
aiLayout->addRow(tr("Summarize language:"), m_summarizeLanguageCombo);
|
||||
|
||||
m_summarySavePathEdit = new QLineEdit();
|
||||
m_summarySavePathEdit->setPlaceholderText(tr("Select folder for AI summaries..."));
|
||||
if (m_preferencesService) {
|
||||
m_summarySavePathEdit->setText(m_preferencesService->aiSummarySavePath());
|
||||
}
|
||||
m_summarySavePathBtn = new QPushButton(tr("Browse..."));
|
||||
connect(m_summarySavePathBtn, &QPushButton::clicked, this, [this]() {
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Select Summary Save Folder"),
|
||||
m_summarySavePathEdit->text());
|
||||
if (!path.isEmpty()) {
|
||||
m_summarySavePathEdit->setText(path);
|
||||
if (m_preferencesService) {
|
||||
m_preferencesService->setAiSummarySavePath(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
QHBoxLayout *pathLayout = new QHBoxLayout();
|
||||
pathLayout->addWidget(m_summarySavePathEdit);
|
||||
pathLayout->addWidget(m_summarySavePathBtn);
|
||||
aiLayout->addRow(tr("Summary save path:"), pathLayout);
|
||||
layout->addWidget(aiGroup);
|
||||
|
||||
layout->addStretch();
|
||||
return widget;
|
||||
}
|
||||
void SettingsView::setAccountService(AccountService *service) {
|
||||
m_accountService = service;
|
||||
if (m_accountService) {
|
||||
|
||||
Reference in New Issue
Block a user