Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ set(PROJECT_SOURCES
include/ui/mainwindow.ui
include/ui/widget/StartStopButton.hpp
src/ui/widget/StartStopButton.cpp
include/ui/widget/TrayPopupFrame.hpp
src/ui/widget/TrayPopupFrame.cpp
include/ui/widget/TrayProfileSelector.hpp
src/ui/widget/TrayProfileSelector.cpp
include/ui/widget/TrayOtpCodes.hpp
Expand Down
6 changes: 4 additions & 2 deletions include/ui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#ifndef MW_INTERFACE

#include <optional>
#include <QKeyEvent>
#include <QSystemTrayIcon>
#include <QPointer>
Expand All @@ -38,6 +39,7 @@

#include "group/GroupSort.hpp"
#include "include/global/GuiUtils.hpp"
#include "include/ui/setting/Icon.hpp"
#include "include/ui/utils/DataViewHtmlGenerator.h"
#include "include/ui/utils/ProfilesFilterProxyModel.h"
#include "include/ui/utils/ProfilesTableModel.h"
Expand Down Expand Up @@ -240,7 +242,7 @@ private slots:
QTextDocument *qvLogDocument = new QTextDocument(this);
//
QString title_error;
int icon_status = -1;
std::optional<Icon::TrayIconStatus> icon_status;
std::shared_ptr<Configs::Profile> running;
int last_running_profile_id = -1;
bool m_profileConnecting = false;
Expand Down Expand Up @@ -473,7 +475,7 @@ private slots:
};

inline MainWindow *GetMainWindow() {
return (MainWindow *) mainwindow;
return qobject_cast<MainWindow *>(mainwindow);
}

void UI_InitMainWindow();
Expand Down
22 changes: 13 additions & 9 deletions include/ui/setting/Icon.hpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
#pragma once

#include <QPixmap>
#include <QIcon>

namespace Icon {

enum TrayIconStatus {
NONE,
RUNNING,
SYSTEM_PROXY,
VPN,
DNS,
SYSTEM_PROXY_DNS,
enum class TrayIconStatus {
None,
Running,
SystemProxy,
Vpn,
Dns,
SystemProxyDns,
};

QPixmap GetTrayIcon(TrayIconStatus status);
QIcon GetTrayIcon(TrayIconStatus status);

// Drop cached icons so the next GetTrayIcon reloads from disk/resources.
// Call when custom-icon files are replaced or the custom-icon setting flips.
void InvalidateTrayIconCache();
} // namespace Icon
2 changes: 1 addition & 1 deletion include/ui/setting/ThemeManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ class ThemeManager : public QObject {
void themeChanged(QString themeName);
};

extern ThemeManager *themeManager;
ThemeManager *themeManager();
5 changes: 4 additions & 1 deletion include/ui/utils/ProfilesTableFilterHeader.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#pragma once


#include <array>

#include <QHeaderView>
#include <QKeyEvent>
#include <QLineEdit>
Expand Down Expand Up @@ -169,7 +172,7 @@ public slots:
void closeRequested();

private:
QVector<QLineEdit*> filterEdits() const {
std::array<QLineEdit*, 4> filterEdits() const {
return {type_filter, address_filter, name_filter, test_filter};
}

Expand Down
16 changes: 4 additions & 12 deletions include/ui/widget/TrayOtpCodes.hpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
#pragma once

#include <QFrame>
#include <QList>
#include <QString>
#include <memory>

#include "include/database/entities/OtpProfile.h"
#include "include/ui/widget/TrayPopupFrame.hpp"

class QLineEdit;
class QListWidget;
class QListWidgetItem;
class QTimer;

// A real window, not a tray submenu, for the reason given on TrayProfileSelector.
class TrayOtpCodes : public QFrame {
class TrayOtpCodes : public TrayPopupFrame {
Q_OBJECT

public:
explicit TrayOtpCodes(QWidget *parent = nullptr);

void popupAt(const QPoint &globalPos);

protected:
void keyPressEvent(QKeyEvent *event) override;

bool eventFilter(QObject *watched, QEvent *event) override;

void preparePopup() override;

private:
void reload();

Expand All @@ -36,10 +32,6 @@ class TrayOtpCodes : public QFrame {

void copyCurrent(const QListWidgetItem *item);

QLineEdit *search = nullptr;

QListWidget *list = nullptr;

QTimer *ticker = nullptr;

QList<std::shared_ptr<Configs::OtpProfile>> profiles;
Expand Down
41 changes: 41 additions & 0 deletions include/ui/widget/TrayPopupFrame.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <QFrame>

class QKeyEvent;
class QLineEdit;
class QListWidget;
class QVBoxLayout;

// Shared chrome for the system-tray popups (profile picker, OTP codes): a
// frameless always-on-top tool window, a rounded card, a search row with a
// close button, and screen-clamped positioning.
//
// Subclasses own the list (and any extra header/footer) and the data that
// fills it. Search/list keyboard handling that is common (Esc, Down from the
// search box) lives here; item activation stays in the subclass.
class TrayPopupFrame : public QFrame {
Q_OBJECT

public:
explicit TrayPopupFrame(QWidget *parent = nullptr);

// Rebuild contents, size to fit, place near globalPos (kept fully on the
// containing screen), then show and focus the search box.
void popupAt(const QPoint &globalPos);

protected:
void keyPressEvent(QKeyEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;

virtual void preparePopup() = 0;
virtual void afterShow() {}

void clearSearch();
void setListWidget(QListWidget *list);

QFrame *m_card = nullptr;
QVBoxLayout *m_cardLayout = nullptr;
QLineEdit *m_search = nullptr;
QListWidget *m_list = nullptr;
};
16 changes: 5 additions & 11 deletions include/ui/widget/TrayProfileSelector.hpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
#pragma once

#include <QFrame>
#include <QString>
#include <QStringList>
#include <QList>
#include <functional>
#include <utility>

#include "include/ui/widget/TrayPopupFrame.hpp"

class QLabel;
class QLineEdit;
class QListWidget;
class QListWidgetItem;
class QPushButton;
class QTimer;
Expand All @@ -26,7 +25,7 @@ class QTimer;
// Behaviour: a rounded card with a debounced search box on top over a compact, paginated
// list. A single click (or Enter) selects; it closes when it loses focus (like a menu) and
// also has an explicit Close button.
class TrayProfileSelector : public QFrame {
class TrayProfileSelector : public TrayPopupFrame {
Q_OBJECT
public:
enum Mode { Server, Routing };
Expand All @@ -45,14 +44,11 @@ class TrayProfileSelector : public QFrame {

TrayProfileSelector(Mode mode, Callbacks cb, QWidget *parent = nullptr);

// Show the panel anchored near globalPos (kept fully on the containing screen) and
// focus the search box. Resets navigation/search to the top level first.
void popupAt(const QPoint &globalPos);

protected:
bool event(QEvent *e) override; // close when the panel loses activation
void keyPressEvent(QKeyEvent *e) override; // Esc closes
bool eventFilter(QObject *obj, QEvent *e) override; // list/search key handling
void preparePopup() override;
void afterShow() override;

private:
void rebuild(); // repopulate for the current view/query/page
Expand Down Expand Up @@ -80,12 +76,10 @@ class TrayProfileSelector : public QFrame {
QList<std::pair<int, QString>> m_routeCache;
QStringList m_routeCacheLower;

QLineEdit *m_search = nullptr;
QTimer *m_debounce = nullptr;
QPushButton *m_backBtn = nullptr;
QLabel *m_title = nullptr;
QPushButton *m_stopBtn = nullptr;
QListWidget *m_list = nullptr;
QPushButton *m_prevBtn = nullptr;
QLabel *m_pageLabel = nullptr;
QPushButton *m_nextBtn = nullptr;
Expand Down
5 changes: 4 additions & 1 deletion res/translations/ru_RU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5443,7 +5443,7 @@ Your local edits are overwritten on each update.</source>
</message>
</context>
<context>
<name>TrayProfileSelector</name>
<name>TrayPopupFrame</name>
<message>
<source>Search…</source>
<translation>Поиск…</translation>
Expand All @@ -5452,6 +5452,9 @@ Your local edits are overwritten on each update.</source>
<source>Close</source>
<translation>Закрыть</translation>
</message>
</context>
<context>
<name>TrayProfileSelector</name>
<message>
<source>Back to groups</source>
<translation>Назад к группам</translation>
Expand Down
5 changes: 4 additions & 1 deletion res/translations/zh_CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5489,7 +5489,7 @@ Your local edits are overwritten on each update.</source>
</message>
</context>
<context>
<name>TrayProfileSelector</name>
<name>TrayPopupFrame</name>
<message>
<source>Search…</source>
<translation>搜索...</translation>
Expand All @@ -5498,6 +5498,9 @@ Your local edits are overwritten on each update.</source>
<source>Close</source>
<translation>关闭</translation>
</message>
</context>
<context>
<name>TrayProfileSelector</name>
<message>
<source>Back to groups</source>
<translation>返回分组</translation>
Expand Down
Loading