mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
VPN: Widget Implementation
This commit is contained in:
committed by
Georgi Velev
parent
1a2ddbb9e3
commit
1cbc793087
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Bluetooth aktivieren",
|
||||
"enable-dnd": "Nicht stören aktivieren",
|
||||
"enable-wifi": "WLAN aktivieren",
|
||||
"connect-vpn": "Mit {name} verbinden",
|
||||
"disconnect-vpn": "Verbindung zu {name} trennen",
|
||||
"next": "Nächste/r/s",
|
||||
"open-calendar": "Kalender öffnen",
|
||||
"open-display-settings": "Anzeigeeinstellungen",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Deaktiviert",
|
||||
"disconnected": "Getrennt von '{ssid}'",
|
||||
"enabled": "Aktiviert"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Verbunden mit '{name}'",
|
||||
"disconnected": "Verbindung zu '{name}' getrennt"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Wach halten",
|
||||
"keyboard-layout": "{layout} Tastaturlayout",
|
||||
"manage-wifi": "WLAN verwalten",
|
||||
"manage-vpn": "VPN-Verbindungen verwalten",
|
||||
"microphone-volume-at": "Mikrofonlautstärke bei {volume}%.\nLinksklick für Einstellungen. Rechtsklick zum Stummschalten.\nScrollen zum Ändern der Lautstärke.",
|
||||
"move-to-center-section": "Zur mittleren Sektion verschieben",
|
||||
"move-to-left-section": "Zur linken Sektion verschieben",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Enable Bluetooth",
|
||||
"enable-dnd": "Enable Do Not Disturb",
|
||||
"enable-wifi": "Enable Wi-Fi",
|
||||
"connect-vpn": "Connect to {name}",
|
||||
"disconnect-vpn": "Disconnect {name}",
|
||||
"next": "Next",
|
||||
"open-calendar": "Open calendar",
|
||||
"open-display-settings": "Display settings",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Disabled",
|
||||
"disconnected": "Disconnected from '{ssid}'",
|
||||
"enabled": "Enabled"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Connected to '{name}'",
|
||||
"disconnected": "Disconnected from '{name}'"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Keep awake",
|
||||
"keyboard-layout": "{layout} keyboard layout",
|
||||
"manage-wifi": "Manage Wi-Fi",
|
||||
"manage-vpn": "Manage VPN connections",
|
||||
"microphone-volume-at": "Microphone volume at {volume}%\nScroll to modify volume",
|
||||
"move-to-center-section": "Move to center section",
|
||||
"move-to-left-section": "Move to left section",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Activar Bluetooth",
|
||||
"enable-dnd": "Activar No molestar",
|
||||
"enable-wifi": "Activar Wi-Fi",
|
||||
"connect-vpn": "Conectarse a {name}",
|
||||
"disconnect-vpn": "Desconectar {name}",
|
||||
"next": "Siguiente",
|
||||
"open-calendar": "Abrir calendario",
|
||||
"open-display-settings": "Configuración de pantalla",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Desactivado",
|
||||
"disconnected": "Desconectado de '{ssid}'",
|
||||
"enabled": "Activado"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Conectado a '{name}'",
|
||||
"disconnected": "Desconectado de '{name}'"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Mantener despierto",
|
||||
"keyboard-layout": "Distribución de teclado {layout}",
|
||||
"manage-wifi": "Gestionar Wi-Fi",
|
||||
"manage-vpn": "Administrar conexiones VPN",
|
||||
"microphone-volume-at": "Volumen del micrófono al {volume}%.\nClic izquierdo para ajustes. Clic derecho para activar/desactivar el silencio.\nDesplázate para modificar el volumen.",
|
||||
"move-to-center-section": "Mover a la sección central",
|
||||
"move-to-left-section": "Mover a la sección izquierda",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Activer le Bluetooth",
|
||||
"enable-dnd": "Activer le mode Ne pas déranger",
|
||||
"enable-wifi": "Activer le Wi-Fi",
|
||||
"connect-vpn": "Se connecter à {name}",
|
||||
"disconnect-vpn": "Se déconnecter de {name}",
|
||||
"next": "Suivant",
|
||||
"open-calendar": "Ouvrir le calendrier",
|
||||
"open-display-settings": "Paramètres d'affichage",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Désactivé",
|
||||
"disconnected": "Déconnecté de '{ssid}'",
|
||||
"enabled": "Activé"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Connecté à '{name}'",
|
||||
"disconnected": "Déconnecté de '{name}'"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Rester éveillé",
|
||||
"keyboard-layout": "Disposition du clavier {layout}",
|
||||
"manage-wifi": "Gérer le Wi-Fi",
|
||||
"manage-vpn": "Gérer les connexions VPN",
|
||||
"microphone-volume-at": "Volume du microphone à {volume}%.\nClic gauche pour les paramètres. Clic droit pour activer/désactiver le mode muet.\nFaites défiler pour modifier le volume.",
|
||||
"move-to-center-section": "Déplacer vers la section centrale",
|
||||
"move-to-left-section": "Déplacer vers la section de gauche",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Bluetooth inschakelen",
|
||||
"enable-dnd": "Niet Storen inschakelen",
|
||||
"enable-wifi": "Wi-Fi inschakelen",
|
||||
"connect-vpn": "Verbinding maken met {name}",
|
||||
"disconnect-vpn": "Verbinding met {name} verbreken",
|
||||
"next": "Volgende",
|
||||
"open-calendar": "Open agenda",
|
||||
"open-display-settings": "Beeldscherminstellingen",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Wi-Fi uitgeschakeld",
|
||||
"disconnected": "Verbinding met '{ssid}' verbroken",
|
||||
"enabled": "Wi-Fi ingeschakeld"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Verbonden met '{name}'",
|
||||
"disconnected": "Verbinding met '{name}' verbroken"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Wakker houden",
|
||||
"keyboard-layout": "{layout}-toetsenbordindeling",
|
||||
"manage-wifi": "Wi-Fi beheren",
|
||||
"manage-vpn": "VPN-verbindingen beheren",
|
||||
"microphone-volume-at": "Microfoonvolume {volume}%\nLinks klikken voor instellingen. Rechts klikken om te dempen.\nScroll om het volume aan te passen.",
|
||||
"move-to-center-section": "Verplaatsen naar middelste sectie",
|
||||
"move-to-left-section": "Verplaatsen naar linker sectie",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Ativar Bluetooth",
|
||||
"enable-dnd": "Ativar Não Perturbe",
|
||||
"enable-wifi": "Ativar Wi-Fi",
|
||||
"connect-vpn": "Conectar-se a {name}",
|
||||
"disconnect-vpn": "Desconectar {name}",
|
||||
"next": "Próximo(a)",
|
||||
"open-calendar": "Abrir calendário",
|
||||
"open-display-settings": "Configurações de exibição",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Desativado",
|
||||
"disconnected": "Desconectado de '{ssid}'",
|
||||
"enabled": "Ativado"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Conectado a '{name}'",
|
||||
"disconnected": "Desconectado de '{name}'"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Manter acordado",
|
||||
"keyboard-layout": "Layout de teclado {layout}",
|
||||
"manage-wifi": "Gerenciar Wi-Fi",
|
||||
"manage-vpn": "Gerenciar conexões VPN",
|
||||
"microphone-volume-at": "Volume do microfone em {volume}%.\nClique esquerdo para configurações. Clique direito para ativar/desativar o mudo.\nRole para modificar o volume.",
|
||||
"move-to-center-section": "Mover para a seção central",
|
||||
"move-to-left-section": "Mover para a seção esquerda",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Включить Bluetooth",
|
||||
"enable-dnd": "Не беспокоить",
|
||||
"enable-wifi": "Включить Wi-Fi",
|
||||
"connect-vpn": "Подключиться к {name}",
|
||||
"disconnect-vpn": "Отключить {name}",
|
||||
"next": "Следующий",
|
||||
"open-calendar": "Открыть календарь",
|
||||
"open-display-settings": "Настройки экрана",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Отключен",
|
||||
"disconnected": "Отключено от '{ssid}'",
|
||||
"enabled": "Включен"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Подключено к '{name}'",
|
||||
"disconnected": "Отключено от '{name}'"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Не засыпать",
|
||||
"keyboard-layout": "Раскладка клавиатуры {layout}",
|
||||
"manage-wifi": "Управление Wi-Fi",
|
||||
"manage-vpn": "Управлять VPN-подключениями",
|
||||
"microphone-volume-at": "Громкость микрофона {volume}%\nЛевый клик для настроек. Правый клик для переключения заглушения.\nПрокрутка для изменения громкости.",
|
||||
"move-to-center-section": "Переместить в центральную секцию",
|
||||
"move-to-left-section": "Переместить в левую секцию",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Bluetooth'u etkinleştir",
|
||||
"enable-dnd": "Rahatsız Etmeyin'i Etkinleştir",
|
||||
"enable-wifi": "Wi-Fi'ı etkinleştir",
|
||||
"connect-vpn": "{name} bağlantısına bağlan",
|
||||
"disconnect-vpn": "{name} bağlantısını kes",
|
||||
"next": "Sonraki",
|
||||
"open-calendar": "Takvimi aç",
|
||||
"open-display-settings": "Ekran ayarları",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Devre dışı",
|
||||
"disconnected": "'{ssid}' bağlantısı kesildi",
|
||||
"enabled": "Etkin"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "'{name}' ile bağlantı kuruldu",
|
||||
"disconnected": "'{name}' bağlantısı kesildi"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Uyanık kal",
|
||||
"keyboard-layout": "{layout} klavye düzeni",
|
||||
"manage-wifi": "Wi-Fi yönet",
|
||||
"manage-vpn": "VPN bağlantılarını yönet",
|
||||
"microphone-volume-at": "Mikrofon sesi %{volume}\nAyarlar için sol tık. Sessize almak için sağ tık.\nSesi değiştirmek için kaydırın.",
|
||||
"move-to-center-section": "Orta bölüme taşı",
|
||||
"move-to-left-section": "Sol bölüme taşı",
|
||||
|
||||
@@ -435,6 +435,8 @@
|
||||
"enable-bluetooth": "Увімкнути Bluetooth",
|
||||
"enable-dnd": "Увімкнути режим \"Не турбувати\"",
|
||||
"enable-wifi": "Увімкнути Wi-Fi",
|
||||
"connect-vpn": "Підключитися до {name}",
|
||||
"disconnect-vpn": "Відключити {name}",
|
||||
"next": "Наступний",
|
||||
"open-calendar": "Відкрити календар",
|
||||
"open-display-settings": "Параметри дисплея",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "Вимкнено",
|
||||
"disconnected": "Відключено від '{ssid}'",
|
||||
"enabled": "Увімкнено"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "Підключено до '{name}'",
|
||||
"disconnected": "Відключено від '{name}'"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "Не спати",
|
||||
"keyboard-layout": "Розкладка клавіатури {layout}",
|
||||
"manage-wifi": "Керувати Wi-Fi",
|
||||
"manage-vpn": "Керувати підключеннями VPN",
|
||||
"microphone-volume-at": "Гучність мікрофона на {volume}%\nЛівий клік для налаштувань. Правий клік для вимкнення звуку.\nПрокрутка для зміни гучності.",
|
||||
"move-to-center-section": "Перемістити в центральну секцію",
|
||||
"move-to-left-section": "Перемістити в ліву секцію",
|
||||
|
||||
@@ -436,6 +436,8 @@
|
||||
"enable-dnd": "启用勿扰模式",
|
||||
"enable-wifi": "启用 Wi-Fi",
|
||||
"next": "下一首",
|
||||
"disconnect-vpn": "断开 {name}",
|
||||
"connect-vpn": "连接 {name}",
|
||||
"open-calendar": "打开日历",
|
||||
"open-display-settings": "显示设置",
|
||||
"open-launcher": "打开启动器",
|
||||
@@ -2053,6 +2055,10 @@
|
||||
"disabled": "已禁用",
|
||||
"disconnected": "已断开与 '{ssid}' 的连接",
|
||||
"enabled": "已启用"
|
||||
},
|
||||
"vpn": {
|
||||
"connected": "已连接到“{name}”",
|
||||
"disconnected": "已断开与“{name}”的连接"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
@@ -2076,6 +2082,7 @@
|
||||
"keep-awake": "保持唤醒",
|
||||
"keyboard-layout": "{layout} 键盘布局",
|
||||
"manage-wifi": "管理 Wi-Fi",
|
||||
"manage-vpn": "管理 VPN 连接",
|
||||
"microphone-volume-at": "麦克风音量 {volume}%\n左键点击进入设置。右键点击切换静音。\n滚动滚轮调节音量。",
|
||||
"move-to-center-section": "移动到中央部分",
|
||||
"move-to-left-section": "移动到左侧部分",
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Modules.Bar.Extras
|
||||
import qs.Services.Networking
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
|
||||
property string widgetId: ""
|
||||
property string section: ""
|
||||
property int sectionWidgetIndex: -1
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.data.bar.widgets[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||
readonly property string displayMode: widgetSettings.displayMode !== undefined ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
|
||||
implicitWidth: pill.width
|
||||
implicitHeight: pill.height
|
||||
|
||||
NPopupContextMenu {
|
||||
id: contextMenu
|
||||
|
||||
model: {
|
||||
const items = [];
|
||||
const active = VPNService.activeConnections;
|
||||
for (let i = 0; i < active.length; ++i) {
|
||||
const conn = active[i];
|
||||
items.push({
|
||||
"label": I18n.tr("context-menu.disconnect-vpn", {
|
||||
"name": conn.name
|
||||
}),
|
||||
"action": "disconnect:" + conn.uuid,
|
||||
"icon": "shield-off"
|
||||
});
|
||||
}
|
||||
const inactive = VPNService.inactiveConnections;
|
||||
for (let i = 0; i < inactive.length; ++i) {
|
||||
const conn = inactive[i];
|
||||
items.push({
|
||||
"label": I18n.tr("context-menu.connect-vpn", {
|
||||
"name": conn.name
|
||||
}),
|
||||
"action": "connect:" + conn.uuid,
|
||||
"icon": "shield-lock"
|
||||
});
|
||||
}
|
||||
items.push({
|
||||
"label": I18n.tr("context-menu.widget-settings"),
|
||||
"action": "widget-settings",
|
||||
"icon": "settings"
|
||||
});
|
||||
return items;
|
||||
}
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
if (action === "widget-settings") {
|
||||
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
|
||||
return;
|
||||
}
|
||||
if (action.startsWith("connect:")) {
|
||||
const uuid = action.substring("connect:".length);
|
||||
VPNService.connect(uuid);
|
||||
return;
|
||||
}
|
||||
if (action.startsWith("disconnect:")) {
|
||||
const uuid = action.substring("disconnect:".length);
|
||||
VPNService.disconnect(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BarPill {
|
||||
id: pill
|
||||
|
||||
screen: root.screen
|
||||
density: Settings.data.bar.density
|
||||
oppositeDirection: BarService.getPillDirection(root)
|
||||
icon: VPNService.hasActiveConnection ? "shield-lock" : "shield"
|
||||
text: {
|
||||
if (VPNService.activeConnections.length > 0) {
|
||||
return VPNService.activeConnections[0].name;
|
||||
}
|
||||
if (VPNService.connectingUuid) {
|
||||
const pending = VPNService.connections[VPNService.connectingUuid];
|
||||
if (pending) {
|
||||
return pending.name;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
suffix: {
|
||||
if (VPNService.activeConnections.length > 1) {
|
||||
return ` + ${VPNService.activeConnections.length - 1}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
autoHide: false
|
||||
forceOpen: !isBarVertical && root.displayMode === "alwaysShow"
|
||||
forceClose: isBarVertical || root.displayMode === "alwaysHide" || !pill.text
|
||||
onClicked: PanelService.getPanel("vpnPanel", screen)?.toggle(this)
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
|
||||
contextMenu.openAtItem(pill, pos.x, pos.y);
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
}
|
||||
}
|
||||
tooltipText: {
|
||||
if (pill.text !== "") {
|
||||
return pill.text;
|
||||
}
|
||||
return I18n.tr("tooltips.manage-vpn");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginM
|
||||
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, widgetData || {});
|
||||
settings.displayMode = valueDisplayMode;
|
||||
return settings;
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
label: I18n.tr("bar.widget-settings.battery.display-mode.label")
|
||||
description: I18n.tr("bar.widget-settings.battery.display-mode.description")
|
||||
minimumWidth: 134
|
||||
model: [
|
||||
{
|
||||
"key": "onhover",
|
||||
"name": I18n.tr("options.display-mode.on-hover")
|
||||
},
|
||||
{
|
||||
"key": "alwaysShow",
|
||||
"name": I18n.tr("options.display-mode.always-show")
|
||||
},
|
||||
{
|
||||
"key": "alwaysHide",
|
||||
"name": I18n.tr("options.display-mode.always-hide")
|
||||
}
|
||||
]
|
||||
currentKey: root.valueDisplayMode
|
||||
onSelected: key => root.valueDisplayMode = key
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Services.UI
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property var connections: ({})
|
||||
property bool refreshing: false
|
||||
property bool connecting: false
|
||||
property bool disconnecting: false
|
||||
property string connectingUuid: ""
|
||||
property string disconnectingUuid: ""
|
||||
property string lastError: ""
|
||||
property bool refreshPending: false
|
||||
|
||||
readonly property var activeConnections: {
|
||||
const result = [];
|
||||
const map = connections;
|
||||
for (const key in map) {
|
||||
const conn = map[key];
|
||||
if (conn && conn.active) {
|
||||
result.push(conn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
readonly property var inactiveConnections: {
|
||||
const result = [];
|
||||
const map = connections;
|
||||
for (const key in map) {
|
||||
const conn = map[key];
|
||||
if (conn && !conn.active) {
|
||||
result.push(conn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
readonly property bool hasActiveConnection: activeConnections.length > 0
|
||||
|
||||
Timer {
|
||||
id: refreshTimer
|
||||
interval: 5000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: refresh()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: delayedRefreshTimer
|
||||
interval: 1000
|
||||
repeat: false
|
||||
onTriggered: refresh()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.i("VPN", "Service started");
|
||||
refresh();
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
if (refreshing) {
|
||||
refreshPending = true;
|
||||
return;
|
||||
}
|
||||
refreshing = true;
|
||||
lastError = "";
|
||||
refreshProcess.running = true;
|
||||
}
|
||||
|
||||
function connect(uuid) {
|
||||
if (connecting || !uuid) {
|
||||
return;
|
||||
}
|
||||
const conn = connections[uuid];
|
||||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
connecting = true;
|
||||
connectingUuid = uuid;
|
||||
lastError = "";
|
||||
connectProcess.uuid = uuid;
|
||||
connectProcess.name = conn.name;
|
||||
connectProcess.running = true;
|
||||
}
|
||||
|
||||
function disconnect(uuid) {
|
||||
if (disconnecting || !uuid) {
|
||||
return;
|
||||
}
|
||||
const conn = connections[uuid];
|
||||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
disconnecting = true;
|
||||
disconnectingUuid = uuid;
|
||||
lastError = "";
|
||||
disconnectProcess.uuid = uuid;
|
||||
disconnectProcess.name = conn.name;
|
||||
disconnectProcess.running = true;
|
||||
}
|
||||
|
||||
function toggle(uuid) {
|
||||
const conn = connections[uuid];
|
||||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
if (conn.active) {
|
||||
disconnect(uuid);
|
||||
} else {
|
||||
connect(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
function setConnection(uuid, data) {
|
||||
if (!uuid) {
|
||||
return;
|
||||
}
|
||||
const map = Object.assign({}, connections);
|
||||
if (map[uuid]) {
|
||||
map[uuid] = Object.assign({}, map[uuid], data);
|
||||
connections = map;
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleRefresh(interval) {
|
||||
delayedRefreshTimer.interval = interval;
|
||||
delayedRefreshTimer.restart();
|
||||
}
|
||||
|
||||
Process {
|
||||
id: refreshProcess
|
||||
running: false
|
||||
command: ["nmcli", "-t", "-f", "NAME,UUID,TYPE,DEVICE", "connection", "show"]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const lines = text.split("\n");
|
||||
const map = {};
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
const line = lines[i].trim();
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
const lastColonIdx = line.lastIndexOf(":");
|
||||
if (lastColonIdx === -1) {
|
||||
continue;
|
||||
}
|
||||
const device = line.substring(lastColonIdx + 1);
|
||||
const remaining = line.substring(0, lastColonIdx);
|
||||
const secondLastColonIdx = remaining.lastIndexOf(":");
|
||||
if (secondLastColonIdx === -1) {
|
||||
continue;
|
||||
}
|
||||
const type = remaining.substring(secondLastColonIdx + 1);
|
||||
if (type !== "vpn") {
|
||||
continue;
|
||||
}
|
||||
const remaining2 = remaining.substring(0, secondLastColonIdx);
|
||||
const thirdLastColonIdx = remaining2.lastIndexOf(":");
|
||||
if (thirdLastColonIdx === -1) {
|
||||
continue;
|
||||
}
|
||||
const uuid = remaining2.substring(thirdLastColonIdx + 1);
|
||||
const name = remaining2.substring(0, thirdLastColonIdx);
|
||||
if (!uuid || !name) {
|
||||
continue;
|
||||
}
|
||||
const active = device && device !== "--";
|
||||
map[uuid] = {
|
||||
"uuid": uuid,
|
||||
"name": name,
|
||||
"device": device,
|
||||
"active": active
|
||||
};
|
||||
}
|
||||
connections = map;
|
||||
const pending = refreshPending;
|
||||
refreshing = false;
|
||||
refreshPending = false;
|
||||
if (pending) {
|
||||
scheduleRefresh(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const pending = refreshPending;
|
||||
refreshing = false;
|
||||
refreshPending = false;
|
||||
if (text.trim()) {
|
||||
lastError = text.split("\n")[0].trim();
|
||||
Logger.w("VPN", "Refresh error: " + text);
|
||||
}
|
||||
if (pending) {
|
||||
scheduleRefresh(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: connectProcess
|
||||
property string uuid: ""
|
||||
property string name: ""
|
||||
running: false
|
||||
command: ["nmcli", "connection", "up", "uuid", uuid]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const output = text.trim();
|
||||
if (!output || (!output.includes("successfully activated") && !output.includes("Connection successfully"))) {
|
||||
return;
|
||||
}
|
||||
setConnection(connectProcess.uuid, {
|
||||
"active": true
|
||||
});
|
||||
connecting = false;
|
||||
connectingUuid = "";
|
||||
lastError = "";
|
||||
Logger.i("VPN", "Connected to " + connectProcess.name);
|
||||
ToastService.showNotice(connectProcess.name, I18n.tr("toast.vpn.connected", {
|
||||
"name": connectProcess.name
|
||||
}), "shield-lock");
|
||||
scheduleRefresh(1000);
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const trimmed = text.trim();
|
||||
if (trimmed) {
|
||||
lastError = trimmed.split("\n")[0].trim();
|
||||
Logger.w("VPN", "Connect error: " + trimmed);
|
||||
ToastService.showWarning(connectProcess.name, lastError);
|
||||
}
|
||||
connecting = false;
|
||||
connectingUuid = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: disconnectProcess
|
||||
property string uuid: ""
|
||||
property string name: ""
|
||||
running: false
|
||||
command: ["nmcli", "connection", "down", "uuid", uuid]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
Logger.i("VPN", "Disconnected from " + disconnectProcess.name);
|
||||
setConnection(disconnectProcess.uuid, {
|
||||
"active": false,
|
||||
"device": ""
|
||||
});
|
||||
disconnecting = false;
|
||||
disconnectingUuid = "";
|
||||
lastError = "";
|
||||
ToastService.showNotice(disconnectProcess.name, I18n.tr("toast.vpn.disconnected", {
|
||||
"name": disconnectProcess.name
|
||||
}), "shield-off");
|
||||
scheduleRefresh(1000);
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const trimmed = text.trim();
|
||||
if (trimmed) {
|
||||
lastError = trimmed.split("\n")[0].trim();
|
||||
Logger.w("VPN", "Disconnect error: " + trimmed);
|
||||
ToastService.showWarning(disconnectProcess.name, lastError);
|
||||
}
|
||||
disconnecting = false;
|
||||
disconnectingUuid = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ Singleton {
|
||||
"TaskbarGrouped": taskbarGroupedComponent,
|
||||
"Tray": trayComponent,
|
||||
"Volume": volumeComponent,
|
||||
"VPN": vpnComponent,
|
||||
"WiFi": wiFiComponent,
|
||||
"WallpaperSelector": wallpaperSelectorComponent,
|
||||
"Workspace": workspaceComponent
|
||||
@@ -62,6 +63,7 @@ Singleton {
|
||||
"TaskbarGrouped": "WidgetSettings/TaskbarGroupedSettings.qml",
|
||||
"Tray": "WidgetSettings/TraySettings.qml",
|
||||
"Volume": "WidgetSettings/VolumeSettings.qml",
|
||||
"VPN": "WidgetSettings/VPNSettings.qml",
|
||||
"WiFi": "WidgetSettings/WiFiSettings.qml",
|
||||
"Workspace": "WidgetSettings/WorkspaceSettings.qml"
|
||||
})
|
||||
@@ -200,6 +202,10 @@ Singleton {
|
||||
"pinned": [],
|
||||
"drawerEnabled": true
|
||||
},
|
||||
"VPN": {
|
||||
"allowUserSettings": true,
|
||||
"displayMode": "onhover"
|
||||
},
|
||||
"WiFi": {
|
||||
"allowUserSettings": true,
|
||||
"displayMode": "onhover"
|
||||
@@ -289,6 +295,9 @@ Singleton {
|
||||
property Component volumeComponent: Component {
|
||||
Volume {}
|
||||
}
|
||||
property Component vpnComponent: Component {
|
||||
VPN {}
|
||||
}
|
||||
property Component wiFiComponent: Component {
|
||||
WiFi {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user