// settingsdialog.cpp — Settings dialog with category list #include "settingsdialog.h" #include "networksettingspage.h" #include "databasesettingspage.h" #include "statuspage.h" #include "nodespage.h" #include "soundsettingspage.h" #include "../transport/gui_bridge.h" #include "../../lib/mem.h" #include "../db/db_manager.h" #include "../transport/utun_node.h" extern "C" { #include "../transport/chat_core.h" } #include #include #include #include #include #include #include #include SettingsDialog::SettingsDialog(const QString& configPath, DbManager* db, UtunNode* node, QWidget* parent) : QDialog(parent) , m_configPath(configPath) { setWindowTitle("Settings"); setMinimumSize(760, 460); setModal(true); auto* mainLayout = new QHBoxLayout(this); mainLayout->setSpacing(0); mainLayout->setContentsMargins(0, 0, 0, 0); // --- Left sidebar: category list --- m_categoryList = new QListWidget(this); m_categoryList->setFixedWidth(150); m_categoryList->setStyleSheet( "QListWidget { border: none; border-right: 1px solid palette(mid);" " background: palette(window); font-size: 13px; }" "QListWidget::item { padding: 10px 14px; }" "QListWidget::item:selected { background: #3390EC; color: white; }"); m_categoryList->addItem("Profile"); m_categoryList->addItem("Network"); m_categoryList->addItem("Database"); m_categoryList->addItem("Status"); m_categoryList->addItem("Nodes"); m_categoryList->addItem("Sound"); mainLayout->addWidget(m_categoryList); // --- Right panel: stacked pages --- auto* rightPanel = new QWidget(this); auto* rightLayout = new QVBoxLayout(rightPanel); rightLayout->setContentsMargins(20, 16, 20, 16); rightLayout->setSpacing(0); m_pages = new QStackedWidget(rightPanel); // Profile page auto* profilePage = new QWidget(m_pages); auto* profLayout = new QFormLayout(profilePage); profLayout->setContentsMargins(0, 12, 0, 0); auto* nameLabel = new QLabel("Display name:", profilePage); m_nicknameEdit = new QLineEdit(profilePage); m_nicknameEdit->setPlaceholderText("Your name (shown to others)"); m_nicknameEdit->setMaxLength(32); m_nicknameEdit->setStyleSheet( "QLineEdit { border: 1px solid palette(mid); border-radius: 4px;" " padding: 6px 10px; font-size: 13px; background: palette(base); }"); profLayout->addRow(nameLabel, m_nicknameEdit); m_pages->addWidget(profilePage); // Network page m_networkPage = new NetworkSettingsPage(m_pages); m_pages->addWidget(m_networkPage); // Database page m_databasePage = new DatabaseSettingsPage(db, m_pages); m_pages->addWidget(m_databasePage); // Status page m_statusPage = new StatusPage(node, m_pages); m_pages->addWidget(m_statusPage); // Nodes page m_nodesPage = new NodesPage(db, m_pages); m_pages->addWidget(m_nodesPage); m_soundPage = new SoundSettingsPage(db, m_pages); m_pages->addWidget(m_soundPage); rightLayout->addWidget(m_pages, 1); // --- Bottom buttons --- auto* btnLayout = new QHBoxLayout(); btnLayout->setSpacing(8); btnLayout->addStretch(); auto* cancelBtn = new QPushButton("Cancel", rightPanel); cancelBtn->setFixedWidth(90); cancelBtn->setStyleSheet( "QPushButton { border: 1px solid palette(mid); border-radius: 4px;" " padding: 6px 16px; font-size: 13px; background: palette(button); }" "QPushButton:hover { background: palette(light); }"); connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); btnLayout->addWidget(cancelBtn); m_saveBtn = new QPushButton("Save", rightPanel); m_saveBtn->setFixedWidth(90); m_saveBtn->setDefault(true); m_saveBtn->setStyleSheet( "QPushButton { border: none; border-radius: 4px;" " padding: 6px 16px; font-size: 13px; font-weight: bold;" " background: #3390EC; color: white; }" "QPushButton:hover { background: #2B7ED4; }"); connect(m_saveBtn, &QPushButton::clicked, this, &SettingsDialog::onSave); btnLayout->addWidget(m_saveBtn); rightLayout->addLayout(btnLayout); mainLayout->addWidget(rightPanel, 1); connect(m_categoryList, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryChanged); // Load current values loadProfileFromConfig(m_configPath); m_networkPage->loadFromConfig(m_configPath); m_soundPage->loadFromDb(); m_categoryList->setCurrentRow(0); } void SettingsDialog::loadProfileFromConfig(const QString& path) { QFile f(path); if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return; QTextStream in(&f); while (!in.atEnd()) { QString line = in.readLine().trimmed(); if (line.startsWith("my_node_name=")) { QString nm = line.mid(QString("my_node_name=").size()).trimmed(); m_nicknameEdit->setText(nm); m_oldNickname = nm; break; } } } void SettingsDialog::onCategoryChanged(int row) { m_pages->setCurrentIndex(row); if (row == 2) m_databasePage->refreshStatus(); if (row == 3) m_statusPage->refreshStatus(); if (row == 4) m_nodesPage->refreshNodes(); if (row == 5) m_soundPage->loadFromDb(); } void SettingsDialog::onSave() { QString newName = m_nicknameEdit->text().trimmed(); /* update name in uTun if changed */ if (newName != m_oldNickname) { char* name_copy = u_strdup(newName.toUtf8().constData()); if (name_copy) gui_bridge_post_uasync_fn(chat_core_update_my_name_trampoline, name_copy); m_oldNickname = newName; } // Save nickname to config QFile f(m_configPath); if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { accept(); return; } QString content = f.readAll(); f.close(); QTextStream ts(&content); QStringList lines; while (!ts.atEnd()) lines << ts.readLine(); bool found = false; for (int i = 0; i < lines.size(); i++) { if (lines[i].trimmed().startsWith("my_node_name=")) { lines[i] = "my_node_name=" + newName; found = true; } else if (!found && lines[i].trimmed() == "[global]") { lines.insert(i + 1, "my_node_name=" + newName); found = true; } } if (!found) lines << "my_node_name=" + newName; f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); f.write(lines.join('\n').toUtf8()); f.close(); m_networkPage->saveToConfig(m_configPath); m_soundPage->applyAndSave(); accept(); }