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
120 changes: 120 additions & 0 deletions openvpn3/BarWidget.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services.UI
import qs.Widgets
import qs.Modules.Bar.Extras

Item {
id: root

property var pluginApi: null
property ShellScreen screen
property string widgetId: ""
property string section: ""
property int sectionWidgetIndex: -1
property int sectionWidgetsCount: 0

readonly property var cfg: pluginApi?.pluginSettings || ({})
readonly property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
readonly property var main: pluginApi?.mainInstance ?? ({})

readonly property real connectedCount: root.main.connectedCount ?? 0
readonly property bool isLoading: root.main.isLoading ?? false
readonly property int configCount: (root.main.configList ?? []).length
readonly property bool hasConfigs: root.configCount > 0
readonly property string connectedColor: root.cfg.connectedColor ?? defaults.connectedColor ?? "primary"
readonly property string disconnectedColor: root.cfg.disconnectedColor ?? defaults.disconnectedColor ?? "none"
readonly property string displayMode: root.cfg.displayMode ?? defaults.displayMode ?? "onhover"
readonly property bool hideWhenInactive: root.cfg.hideWhenInactive ?? defaults.hideWhenInactive ?? false
readonly property bool isInactive: root.connectedCount === 0 && !root.isLoading

readonly property bool isHidden: root.hideWhenInactive && root.isInactive

readonly property var sessionList: root.main.sessionList ?? []

readonly property string connectedName: {
if (root.connectedCount !== 1 || root.sessionList.length === 0) return ""
const name = root.sessionList[0]?.name
return (name && name.length > 0) ? name : ""
}

function _tooltipText() {
if (root.isLoading)
return pluginApi?.tr("bar.connecting")
if (root.connectedCount > 0) {
const lines = []
for (let i = 0; i < root.sessionList.length; i++) {
const s = root.sessionList[i]
const name = (s?.name && s.name.length > 0) ? s.name : (s?.sessionPath || "session")
lines.push(name)
}
return lines.join("\n")
}
if (!root.hasConfigs)
return pluginApi?.tr("bar.noConfigs")
return pluginApi?.tr("bar.disconnected")
}

readonly property string pillIcon: {
if (root.isLoading) return "shield-check"
if (root.connectedCount > 0) return "shield-lock"
if (!root.hasConfigs) return "shield-off"
return "shield"
}

readonly property string pillText: {
if (root.connectedCount > 0) {
if (root.connectedCount === 1 && root.connectedName.length > 0)
return root.connectedName
return root.connectedCount + " " + pluginApi?.tr("bar.active")
}
if (root.isLoading) return pluginApi?.tr("bar.connecting")
if (!root.hasConfigs) return pluginApi?.tr("bar.noConfigs")
return pluginApi?.tr("bar.disconnected")
}

opacity: root.isHidden ? 0.0 : 1.0
implicitWidth: root.isHidden ? 0 : pill.width
implicitHeight: root.isHidden ? 0 : pill.height

NPopupContextMenu {
id: contextMenu

model: [{
"label": pluginApi?.tr("menu.settings"),
"action": "plugin-settings",
"icon": "settings"
}]
onTriggered: (action) => {
contextMenu.close()
PanelService.closeContextMenu(screen)
if (action === "plugin-settings")
BarService.openPluginSettings(screen, pluginApi.manifest)
}
}

BarPill {
id: pill

screen: root.screen
oppositeDirection: BarService.getPillDirection(root)
autoHide: false
text: root.pillText
icon: root.pillIcon
tooltipText: root._tooltipText()
customIconColor: Color.resolveColorKeyOptional(root.connectedCount > 0 ? root.connectedColor : root.disconnectedColor)
customTextColor: Color.resolveColorKeyOptional(root.connectedCount > 0 ? root.connectedColor : root.disconnectedColor)
forceOpen: root.displayMode === "alwaysShow"
forceClose: root.displayMode === "alwaysHide"

onClicked: {
if (pluginApi)
pluginApi.togglePanel(root.screen, root)
}
onRightClicked: {
PanelService.showContextMenu(contextMenu, root, screen)
}
}
}
90 changes: 90 additions & 0 deletions openvpn3/ControlCenterWidget.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import QtQuick
import Quickshell
import qs.Commons
import qs.Services.UI
import qs.Widgets

// Custom control-center button so we can use the OpenVPN brand icon
// (NIconButtonHot only accepts built-in icon names)
Item {
id: root

property ShellScreen screen
property var pluginApi: null

readonly property var cfg: pluginApi?.pluginSettings || ({})
readonly property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
readonly property var main: pluginApi?.mainInstance ?? ({})
readonly property real connectedCount: main.connectedCount ?? 0
readonly property bool isLoading: main.isLoading ?? false
readonly property int configCount: (main.configList ?? []).length
readonly property bool hasConfigs: configCount > 0
readonly property bool isConnected: connectedCount > 0
readonly property var sessionList: main.sessionList ?? []
readonly property string connectedColor: cfg.connectedColor ?? defaults.connectedColor ?? "primary"
readonly property string disconnectedColor: cfg.disconnectedColor ?? defaults.disconnectedColor ?? "none"

readonly property color iconColor: {
const key = isConnected ? connectedColor : disconnectedColor
if (!key || key === "none")
return mouseArea.containsMouse ? Color.mOnHover : Color.mPrimary
return Color.resolveColorKeyOptional(key) ?? Color.mPrimary
}

function tipText() {
if (isLoading)
return pluginApi?.tr("bar.connecting")
if (!isConnected) {
if (!hasConfigs)
return pluginApi?.tr("bar.noConfigs")
return pluginApi?.tr("bar.disconnected")
}

const list = sessionList
if (!list || list.length === 0)
return pluginApi?.tr("bar.tooltipDisconnected")

const lines = []
for (let i = 0; i < list.length; i++) {
const s = list[i]
const name = (s?.name && s.name.length > 0) ? s.name : (s?.sessionPath || "session")
let statusLabel = pluginApi?.tr("status.connected")
if (s?.isPaused)
statusLabel = pluginApi?.tr("status.paused")
else if (s?.status && s.status.length > 0)
statusLabel = s.status
lines.push(name)
}
return lines.join("\n")
}

implicitWidth: Style.baseWidgetSize
implicitHeight: Style.baseWidgetSize

Rectangle {
anchors.fill: parent
radius: Style.radiusM
color: mouseArea.containsMouse ? Color.mHover : "transparent"

OpenVpnIcon {
anchors.centerIn: parent
pointSize: Style.fontSizeXXL
applyUiScale: false
color: root.iconColor
opacity: root.isLoading ? 0.5 : 1.0
}
}

MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
TooltipService.hide()
pluginApi?.togglePanel(screen, root)
}
onEntered: TooltipService.show(root, root.tipText())
onExited: TooltipService.hide()
}
}
Loading