diff --git a/include/global/Const.hpp b/include/global/Const.hpp index 3a03fc7..c0fe002 100644 --- a/include/global/Const.hpp +++ b/include/global/Const.hpp @@ -27,6 +27,8 @@ namespace Configs { namespace Information { inline QString HijackInfo = "Listens on the given addr:port (on Windows, port is always 53) and redirects the requests to the DNS module. Domains that match the rules will have their requests hijacked and the A and AAAA queries will be responded with the Inet4 response and Inet6 response respectively.\nThe Redirect settings sets up an inbound that listens on the given addr:port, sniffs the destination if possible and redirects the requests to their true destination.\nThe use case of these settings is apps that do not respect the system proxy for resolving their DNS requests (one such example is discord), You can hijack their DNS requests to 127.0.0.1 and then route them through the Throne tunnel. The same effect could be achieved using Tun mode, but one may not want to tunnel the whole device (For example when Gaming), this is where DNS hijack can transparently handle things.\n\nCurrently you can Automatically set the System DNS in windows."; inline QString SimpleRuleInfo = "You can add rules with the following format:\ndomain:\nsuffix:\nkeyword:\nregex:\nruleset: or ruleset:\nip:\nprocessName:\nprocessPath:\nRules are validated on tab change or when pressing ok.\nImportant: On saving the rules, the previous rules are discarded, meaning\nany changes made to the generated rules in the Advanced tab will be lost."; + inline QString CustomIconManual = "To choose custom icons, you need to choose png images with an equal width and height (eg 512*512). Their names should be of \n(Dns.png, Off.png, Proxy.png, Proxy-Dns.png, Throne.png, Tun.png) So that each will be used in the appropriate state of the app. \nYou can provide a subset of the said images and only the corresponding states will be using them.\nIt is suggested that each image's size be less than 100KB."; + inline QStringList iconNames = {"Dns.png", "Off.png", "Proxy.png", "Proxy-Dns.png", "Throne.png", "Tun.png"}; } namespace TestConfig diff --git a/include/global/DataStore.hpp b/include/global/DataStore.hpp index 7a9e94d..8fdd089 100644 --- a/include/global/DataStore.hpp +++ b/include/global/DataStore.hpp @@ -105,6 +105,7 @@ namespace Configs { QString simple_dl_url = "http://cachefly.cachefly.net/1mb.test"; bool allow_beta_update = false; bool show_system_dns = false; + bool use_custom_icons = false; // Network bool net_use_proxy = false; diff --git a/include/ui/setting/dialog_basic_settings.h b/include/ui/setting/dialog_basic_settings.h index b772007..7da36a2 100644 --- a/include/ui/setting/dialog_basic_settings.h +++ b/include/ui/setting/dialog_basic_settings.h @@ -28,6 +28,7 @@ private: QString custom_inbound; bool needRestart = false; bool updateDisableTray = false; + bool updateTrayIcon = false; bool updateSystemDns = false; } CACHE; diff --git a/include/ui/setting/dialog_basic_settings.ui b/include/ui/setting/dialog_basic_settings.ui index 621b2e7..b7841e6 100644 --- a/include/ui/setting/dialog_basic_settings.ui +++ b/include/ui/setting/dialog_basic_settings.ui @@ -418,8 +418,8 @@ - - + + @@ -432,7 +432,7 @@ - + @@ -441,6 +441,20 @@ + + + + Select + + + + + + + Enable Custom Icons + + + diff --git a/src/global/Configs.cpp b/src/global/Configs.cpp index 7a83026..d6cb19c 100644 --- a/src/global/Configs.cpp +++ b/src/global/Configs.cpp @@ -324,6 +324,7 @@ namespace Configs { _add(new configItem("url_test_timeout_ms", &url_test_timeout_ms, itemType::integer)); _add(new configItem("show_system_dns", &show_system_dns, itemType::boolean)); _add(new configItem("main_window_geometry", &mainWindowGeometry, itemType::string)); + _add(new configItem("use_custom_icons", &use_custom_icons, itemType::boolean)); } void DataStore::UpdateStartedId(int id) { diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a158c5d..1f70c57 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -237,6 +237,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi dashFile.close(); } } + if (auto dashDir = QDir("icons"); !dashDir.exists("icons")) { + QDir().mkdir("icons") ? qDebug("created icons dir") : qDebug("Failed to create icons dir"); + } // top bar ui->toolButton_program->setMenu(ui->menu_program); @@ -760,7 +763,7 @@ void MainWindow::show_group(int gid) { void MainWindow::dialog_message_impl(const QString &sender, const QString &info) { // info - if (info.contains("UpdateIcon")) { + if (info.contains("UpdateTrayIcon")) { icon_status = -1; refresh_status(); } diff --git a/src/ui/setting/Icon.cpp b/src/ui/setting/Icon.cpp index 71f1fb3..679bfd5 100644 --- a/src/ui/setting/Icon.cpp +++ b/src/ui/setting/Icon.cpp @@ -6,35 +6,71 @@ QPixmap Icon::GetTrayIcon(TrayIconStatus status) { QPixmap pixmap; + QPixmap pixmap_read; if (status == NONE) { - auto pixmap_read = QPixmap(QString(":/Throne/") + "Off" + ".png"); + if (Configs::dataStore->use_custom_icons) { + pixmap_read = QPixmap(QString("icons/") + "Off" + ".png"); + } + if (pixmap_read.isNull()) { + pixmap_read = QPixmap(QString(":/Throne/") + "Off" + ".png"); + } if (!pixmap_read.isNull()) pixmap = pixmap_read; } else if (status == RUNNING) { - auto pixmap_read = QPixmap(QString(":/Throne/") + "Throne" + ".png"); + if (Configs::dataStore->use_custom_icons) { + pixmap_read = QPixmap(QString("icons/") + "Throne" + ".png"); + } + if (pixmap_read.isNull()) { + pixmap_read = QPixmap(QString(":/Throne/") + "Throne" + ".png"); + } if (!pixmap_read.isNull()) pixmap = pixmap_read; } else if (status == SYSTEM_PROXY_DNS) { - auto pixmap_read = QPixmap(QString(":/Throne/") + "Proxy-Dns" + ".png"); + if (Configs::dataStore->use_custom_icons) { + pixmap_read = QPixmap(QString("icons/") + "Proxy-Dns" + ".png"); + } + if (pixmap_read.isNull()) { + pixmap_read = QPixmap(QString(":/Throne/") + "Proxy-Dns" + ".png"); + } if (!pixmap_read.isNull()) pixmap = pixmap_read; } else if (status == SYSTEM_PROXY) { - auto pixmap_read = QPixmap(QString(":/Throne/") + "Proxy" + ".png"); + if (Configs::dataStore->use_custom_icons) { + pixmap_read = QPixmap(QString("icons/") + "Proxy" + ".png"); + } + if (pixmap_read.isNull()) { + pixmap_read = QPixmap(QString(":/Throne/") + "Proxy" + ".png"); + } if (!pixmap_read.isNull()) pixmap = pixmap_read; } else if (status == DNS) { - auto pixmap_read = QPixmap(QString(":/Throne/") + "Dns" + ".png"); + if (Configs::dataStore->use_custom_icons) { + pixmap_read = QPixmap(QString("icons/") + "Dns" + ".png"); + } + if (pixmap_read.isNull()) { + pixmap_read = QPixmap(QString(":/Throne/") + "Dns" + ".png"); + } if (!pixmap_read.isNull()) pixmap = pixmap_read; } else if (status == VPN) { - auto pixmap_read = QPixmap(QString(":/Throne/") + "Tun" + ".png"); + if (Configs::dataStore->use_custom_icons) { + pixmap_read = QPixmap(QString("icons/") + "Tun" + ".png"); + } + if (pixmap_read.isNull()) { + pixmap_read = QPixmap(QString(":/Throne/") + "Tun" + ".png"); + } if (!pixmap_read.isNull()) pixmap = pixmap_read; } else { MW_show_log("Icon::GetTrayIcon: Unknown status"); - auto pixmap_read = QPixmap(QString(":/Throne/") + "Off" + ".png"); + if (Configs::dataStore->use_custom_icons) { + pixmap_read = QPixmap(QString("icons/") + "Off" + ".png"); + } + if (pixmap_read.isNull()) { + pixmap_read = QPixmap(QString(":/Throne/") + "Off" + ".png"); + } if (!pixmap_read.isNull()) pixmap = pixmap_read; } diff --git a/src/ui/setting/dialog_basic_settings.cpp b/src/ui/setting/dialog_basic_settings.cpp index e494ca1..b802dbc 100644 --- a/src/ui/setting/dialog_basic_settings.cpp +++ b/src/ui/setting/dialog_basic_settings.cpp @@ -108,6 +108,30 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent) // ui->theme->addItems(QStyleFactory::keys()); ui->theme->addItem("QDarkStyle"); + ui->enable_custom_icon->setChecked(Configs::dataStore->use_custom_icons); + connect(ui->select_custom_icon, &QPushButton::clicked, this, [=, this] { + auto n = QMessageBox::information(this, "Custom Icon Manual", tr(Configs::Information::CustomIconManual.toStdString().c_str()), QMessageBox::Open | QMessageBox::Cancel); + if (n == QMessageBox::Open) { + auto fileNames = QFileDialog::getOpenFileNames(this, + tr("Select png icons"), QDir::homePath(), tr("Image Files (*.png)")); + // process files + QString errors; + for (const auto& fileName : fileNames) { + CACHE.updateTrayIcon = true; + QFileInfo fileInfo(fileName); + if (auto pixMap = QPixmap(fileName); pixMap.isNull()) errors += "Failed to load " + fileName + "\n"; + else if (pixMap.width() != pixMap.height()) errors += "Image does not have equal width and height: " + fileName + "\n"; + else if (!Configs::Information::iconNames.contains(fileInfo.fileName())) errors += "Icon name is not valid: " + fileInfo.fileName() + "\n"; + else { + QFile::remove(QDir("icons").filePath(fileInfo.fileName())); + if (!QFile::copy(fileName, QDir("icons").filePath(fileInfo.fileName()))) errors += "Failed to copy " + fileName + "\n"; + } + } + if (!errors.isEmpty()) { + QMessageBox::warning(this, "Select custom image error", errors); + } + } + }); // bool ok; auto themeId = Configs::dataStore->theme.toInt(&ok); @@ -117,7 +141,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent) ui->theme->setCurrentText(Configs::dataStore->theme); } // - connect(ui->theme, static_cast(&QComboBox::currentIndexChanged), this, [=,this](int index) { + connect(ui->theme, &QComboBox::currentIndexChanged, this, [=,this](int index) { themeManager->ApplyTheme(ui->theme->currentText()); Configs::dataStore->theme = ui->theme->currentText(); Configs::dataStore->Save(); @@ -205,6 +229,9 @@ void DialogBasicSettings::accept() { Configs::dataStore->enable_stats = ui->connection_statistics->isChecked(); Configs::dataStore->language = ui->language->currentIndex(); + auto oldUseCustomIcon = Configs::dataStore->use_custom_icons; + Configs::dataStore->use_custom_icons = ui->enable_custom_icon->isChecked(); + if (oldUseCustomIcon != Configs::dataStore->use_custom_icons) CACHE.updateTrayIcon = true; D_SAVE_BOOL(start_minimal) D_SAVE_INT(max_log_line) Configs::dataStore->show_system_dns = ui->show_sys_dns->isChecked(); @@ -255,6 +282,7 @@ void DialogBasicSettings::accept() { if (CACHE.needRestart) str << "NeedRestart"; if (CACHE.updateDisableTray) str << "UpdateDisableTray"; if (CACHE.updateSystemDns) str << "UpdateSystemDns"; + if (CACHE.updateTrayIcon) str << "UpdateTrayIcon"; if (needChoosePort) str << "NeedChoosePort"; MW_dialog_message(Dialog_DialogBasicSettings, str.join(",")); QDialog::accept();