Feature: Make home UniFi VPN row a collapsible card
Put the Replace config option behind an expand chevron, like Mullvad's options, and frame the card while it's expanded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -66,6 +66,9 @@ Item {
|
||||
property string protonActionStatus: ""
|
||||
property string homeWgActionStatus: ""
|
||||
property bool homeWgImporting: homeWgImportProc.running
|
||||
// Whether Home's options (Replace config) are expanded — kept across
|
||||
// panel opens, like mullvadOptionsOpen.
|
||||
property bool homeWgOptionsOpen: false
|
||||
|
||||
// --- Mullvad advanced options (auto-connect, relay location, multihop) --
|
||||
// ProtonVPN's CLI is plain-text-only and far less predictable across
|
||||
@@ -1006,7 +1009,124 @@ Item {
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 2
|
||||
// Room for the cards' outlines (drawn 3px outside them)
|
||||
// so two expanded ones don't touch.
|
||||
spacing: 8
|
||||
|
||||
// Same collapsible card as Mullvad below — framed only
|
||||
// while its options (Replace config) are expanded.
|
||||
Item {
|
||||
readonly property bool _framed: root.homeWgOptionsOpen && root.homeWgInstalled
|
||||
width: parent.width
|
||||
implicitHeight: homeWgSectionColumn.implicitHeight
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation { duration: Appearance.animationDuration; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
// Outline offset outside the content rather than drawn on
|
||||
// its own edge — same as Volume.qml's DeviceRow hover —
|
||||
// so the row doesn't shift when the options open.
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -3
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
border.color: Colors.foreground
|
||||
border.width: parent._framed ? 1 : 0
|
||||
}
|
||||
|
||||
// Clipped separately so the outline above isn't.
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
id: homeWgSectionColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
spacing: 8
|
||||
|
||||
ProviderRow {
|
||||
label: "Home (UniFi)"
|
||||
subIcon: "home"
|
||||
state: root.homeWgState
|
||||
detailText: root.homeWgDetail
|
||||
installed: root.homeWgInstalled
|
||||
missingText: "Not set up"
|
||||
expandable: root.homeWgInstalled
|
||||
expanded: root.homeWgOptionsOpen
|
||||
onToggle: root.toggleHomeWg()
|
||||
onExpandToggle: root.homeWgOptionsOpen = !root.homeWgOptionsOpen
|
||||
}
|
||||
|
||||
StatusLine { message: root.homeWgActionStatus }
|
||||
|
||||
// Imports (or replaces) the UniFi client .conf through a
|
||||
// file chooser. Shown outright until a profile exists
|
||||
// (so first-time setup isn't hidden behind the
|
||||
// chevron), then only inside the expanded options.
|
||||
// Hidden while connected — replacing deletes the
|
||||
// profile, which would drop the tunnel.
|
||||
Item {
|
||||
width: parent.width
|
||||
implicitHeight: importRow.implicitHeight + 8
|
||||
visible: root.homeWgState === "disconnected"
|
||||
&& (!root.homeWgInstalled || root.homeWgOptionsOpen)
|
||||
|
||||
Row {
|
||||
id: importRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 34
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 4
|
||||
opacity: root.homeWgImporting ? 0.5 : 1
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.homeWgInstalled ? "sync" : "upload_file"
|
||||
font.family: Appearance.iconFontFamilyRounded
|
||||
font.variableAxes: Appearance.iconFontAxes
|
||||
font.pixelSize: 13
|
||||
color: importMouse.containsMouse ? Colors.foreground : Colors.primary
|
||||
}
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.homeWgImporting ? "Choosing file…"
|
||||
: root.homeWgInstalled ? "Replace config" : "Add config"
|
||||
font.family: Appearance.fontFamily
|
||||
font.pixelSize: Appearance.fontSizeSmall
|
||||
font.underline: importMouse.containsMouse
|
||||
color: importMouse.containsMouse ? Colors.foreground : Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: importMouse
|
||||
anchors.fill: importRow
|
||||
anchors.margins: -4
|
||||
enabled: !root.homeWgImporting
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.importHomeWgConfig()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
x: 34
|
||||
width: parent.width - x
|
||||
visible: root.homeWgOptionsOpen && root.homeWgInstalled
|
||||
&& root.homeWgState !== "disconnected"
|
||||
text: "Disconnect to replace config"
|
||||
bottomPadding: 6
|
||||
font.family: Appearance.fontFamily
|
||||
font.pixelSize: Appearance.fontSizeSmall
|
||||
color: Colors.muted
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mullvad's connect row and its advanced options share a
|
||||
// single bordered card — the border wraps the whole
|
||||
@@ -1014,14 +1134,11 @@ Item {
|
||||
// grows to include the options/picker as they open,
|
||||
// rather than the options having a separate box of
|
||||
// their own below an unbordered connect row.
|
||||
Rectangle {
|
||||
// Only outlined while the options are expanded.
|
||||
Item {
|
||||
readonly property bool _framed: root.mullvadOptionsOpen && root.mullvadInstalled
|
||||
width: parent.width
|
||||
radius: 0
|
||||
color: Colors.background
|
||||
border.color: Colors.muted
|
||||
border.width: 1
|
||||
implicitHeight: mullvadSectionColumn.implicitHeight + 16
|
||||
clip: true
|
||||
implicitHeight: mullvadSectionColumn.implicitHeight
|
||||
// Without this, the card snapped to its new size
|
||||
// instantly while the popup around it was still
|
||||
// animating open, so the border visibly lagged
|
||||
@@ -1031,12 +1148,28 @@ Item {
|
||||
NumberAnimation { duration: Appearance.animationDuration; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
// Outline offset outside the content rather than drawn on
|
||||
// its own edge — same as Volume.qml's DeviceRow hover —
|
||||
// so the row doesn't shift when the options open.
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -3
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
border.color: Colors.foreground
|
||||
border.width: parent._framed ? 1 : 0
|
||||
}
|
||||
|
||||
// Clipped separately so the outline above isn't.
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
id: mullvadSectionColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 8
|
||||
spacing: 8
|
||||
|
||||
ProviderRow {
|
||||
@@ -1199,6 +1332,7 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProviderRow {
|
||||
label: "ProtonVPN"
|
||||
@@ -1210,64 +1344,6 @@ Item {
|
||||
}
|
||||
|
||||
StatusLine { message: root.protonActionStatus }
|
||||
|
||||
ProviderRow {
|
||||
label: "Home (UniFi)"
|
||||
subIcon: "home"
|
||||
state: root.homeWgState
|
||||
detailText: root.homeWgDetail
|
||||
installed: root.homeWgInstalled
|
||||
missingText: "Not set up"
|
||||
onToggle: root.toggleHomeWg()
|
||||
}
|
||||
|
||||
StatusLine { message: root.homeWgActionStatus }
|
||||
|
||||
// Imports (or replaces) the UniFi client .conf through a
|
||||
// file chooser. Hidden while connected — replacing
|
||||
// deletes the profile, which would drop the tunnel.
|
||||
Item {
|
||||
width: parent.width
|
||||
implicitHeight: importRow.implicitHeight + 8
|
||||
visible: root.homeWgState === "disconnected"
|
||||
|
||||
Row {
|
||||
id: importRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 34
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 4
|
||||
opacity: root.homeWgImporting ? 0.5 : 1
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.homeWgInstalled ? "sync" : "upload_file"
|
||||
font.family: Appearance.iconFontFamilyRounded
|
||||
font.variableAxes: Appearance.iconFontAxes
|
||||
font.pixelSize: 13
|
||||
color: importMouse.containsMouse ? Colors.foreground : Colors.primary
|
||||
}
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.homeWgImporting ? "Choosing file…"
|
||||
: root.homeWgInstalled ? "Replace config" : "Add config"
|
||||
font.family: Appearance.fontFamily
|
||||
font.pixelSize: Appearance.fontSizeSmall
|
||||
font.underline: importMouse.containsMouse
|
||||
color: importMouse.containsMouse ? Colors.foreground : Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: importMouse
|
||||
anchors.fill: importRow
|
||||
anchors.margins: -4
|
||||
enabled: !root.homeWgImporting
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.importHomeWgConfig()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
|
||||
Reference in New Issue
Block a user