diff options
Diffstat (limited to 'modules/controlcenter')
| -rw-r--r-- | modules/controlcenter/appearance/AppearancePane.qml | 259 | ||||
| -rw-r--r-- | modules/controlcenter/appearance/sections/BackgroundSection.qml | 297 | ||||
| -rw-r--r-- | modules/controlcenter/appearance/sections/ColorSchemeSection.qml | 146 | ||||
| -rw-r--r-- | modules/controlcenter/appearance/sections/FontsSection.qml | 280 | ||||
| -rw-r--r-- | modules/controlcenter/launcher/LauncherPane.qml | 597 | ||||
| -rw-r--r-- | modules/controlcenter/network/NetworkSettings.qml | 72 | ||||
| -rw-r--r-- | modules/controlcenter/network/NetworkingPane.qml | 69 | ||||
| -rw-r--r-- | modules/controlcenter/network/VpnDetails.qml | 367 | ||||
| -rw-r--r-- | modules/controlcenter/network/VpnList.qml | 646 | ||||
| -rw-r--r-- | modules/controlcenter/network/VpnSettings.qml | 232 | ||||
| -rw-r--r-- | modules/controlcenter/state/VpnState.qml | 5 | ||||
| -rw-r--r-- | modules/controlcenter/taskbar/TaskbarPane.qml | 646 |
12 files changed, 5 insertions, 3611 deletions
diff --git a/modules/controlcenter/appearance/AppearancePane.qml b/modules/controlcenter/appearance/AppearancePane.qml deleted file mode 100644 index 822edad..0000000 --- a/modules/controlcenter/appearance/AppearancePane.qml +++ /dev/null @@ -1,259 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../components" -import "./sections" -import "../../launcher/services" -import qs.components -import qs.components.controls -import qs.components.effects -import qs.components.containers -import qs.components.images -import qs.services -import qs.config -import qs.utils -import Caelestia.Models -import Quickshell -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts - -Item { - id: root - - required property Session session - - property real animDurationsScale: Config.appearance.anim.durations.scale ?? 1 - property string fontFamilyMaterial: Config.appearance.font.family.material ?? "Material Symbols Rounded" - property string fontFamilyMono: Config.appearance.font.family.mono ?? "CaskaydiaCove NF" - property string fontFamilySans: Config.appearance.font.family.sans ?? "Rubik" - property real fontSizeScale: Config.appearance.font.size.scale ?? 1 - property real paddingScale: Config.appearance.padding.scale ?? 1 - property real roundingScale: Config.appearance.rounding.scale ?? 1 - property real spacingScale: Config.appearance.spacing.scale ?? 1 - property bool transparencyEnabled: Config.appearance.transparency.enabled ?? false - property real transparencyBase: Config.appearance.transparency.base ?? 0.85 - property real transparencyLayers: Config.appearance.transparency.layers ?? 0.4 - property real borderRounding: Config.border.rounding ?? 1 - property real borderThickness: Config.border.thickness ?? 1 - - property bool desktopClockEnabled: Config.background.desktopClock.enabled ?? false - property real desktopClockScale: Config.background.desktopClock.scale ?? 1 - property string desktopClockPosition: Config.background.desktopClock.position ?? "bottom-right" - property bool desktopClockShadowEnabled: Config.background.desktopClock.shadow.enabled ?? true - property real desktopClockShadowOpacity: Config.background.desktopClock.shadow.opacity ?? 0.7 - property real desktopClockShadowBlur: Config.background.desktopClock.shadow.blur ?? 0.4 - property bool desktopClockBackgroundEnabled: Config.background.desktopClock.background.enabled ?? false - property real desktopClockBackgroundOpacity: Config.background.desktopClock.background.opacity ?? 0.7 - property bool desktopClockBackgroundBlur: Config.background.desktopClock.background.blur ?? false - property bool desktopClockInvertColors: Config.background.desktopClock.invertColors ?? false - property bool backgroundEnabled: Config.background.enabled ?? true - property bool visualiserEnabled: Config.background.visualiser.enabled ?? false - property bool visualiserAutoHide: Config.background.visualiser.autoHide ?? true - property real visualiserRounding: Config.background.visualiser.rounding ?? 1 - property real visualiserSpacing: Config.background.visualiser.spacing ?? 1 - - anchors.fill: parent - - function saveConfig() { - Config.appearance.anim.durations.scale = root.animDurationsScale; - - Config.appearance.font.family.material = root.fontFamilyMaterial; - Config.appearance.font.family.mono = root.fontFamilyMono; - Config.appearance.font.family.sans = root.fontFamilySans; - Config.appearance.font.size.scale = root.fontSizeScale; - - Config.appearance.padding.scale = root.paddingScale; - Config.appearance.rounding.scale = root.roundingScale; - Config.appearance.spacing.scale = root.spacingScale; - - Config.appearance.transparency.enabled = root.transparencyEnabled; - Config.appearance.transparency.base = root.transparencyBase; - Config.appearance.transparency.layers = root.transparencyLayers; - - Config.background.desktopClock.enabled = root.desktopClockEnabled; - Config.background.enabled = root.backgroundEnabled; - Config.background.desktopClock.scale = root.desktopClockScale - Config.background.desktopClock.position = root.desktopClockPosition - Config.background.desktopClock.shadow.enabled = root.desktopClockShadowEnabled - Config.background.desktopClock.shadow.opacity = root.desktopClockShadowOpacity - Config.background.desktopClock.shadow.blur = root.desktopClockShadowBlur - Config.background.desktopClock.background.enabled = root.desktopClockBackgroundEnabled - Config.background.desktopClock.background.opacity = root.desktopClockBackgroundOpacity - Config.background.desktopClock.background.blur = root.desktopClockBackgroundBlur - Config.background.desktopClock.invertColors = root.desktopClockInvertColors - - Config.background.visualiser.enabled = root.visualiserEnabled; - Config.background.visualiser.autoHide = root.visualiserAutoHide; - Config.background.visualiser.rounding = root.visualiserRounding; - Config.background.visualiser.spacing = root.visualiserSpacing; - - Config.border.rounding = root.borderRounding; - Config.border.thickness = root.borderThickness; - - Config.save(); - } - - Component { - id: appearanceRightContentComponent - - Item { - id: rightAppearanceFlickable - - ColumnLayout { - id: contentLayout - - anchors.fill: parent - spacing: 0 - - StyledText { - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: Appearance.spacing.normal - text: qsTr("Wallpaper") - font.pointSize: Appearance.font.size.extraLarge - font.weight: 600 - } - - Loader { - id: wallpaperLoader - - Layout.fillWidth: true - Layout.fillHeight: true - Layout.bottomMargin: -Appearance.padding.large * 2 - - active: { - const isActive = root.session.activeIndex === 3; - const isAdjacent = Math.abs(root.session.activeIndex - 3) === 1; - const splitLayout = root.children[0]; - const loader = splitLayout && splitLayout.rightLoader ? splitLayout.rightLoader : null; - const shouldActivate = loader && loader.item !== null && (isActive || isAdjacent); - return shouldActivate; - } - - onStatusChanged: { - if (status === Loader.Error) { - console.error("[AppearancePane] Wallpaper loader error!"); - } - } - - sourceComponent: WallpaperGrid { - session: root.session - } - } - } - } - } - - SplitPaneLayout { - anchors.fill: parent - - leftContent: Component { - - StyledFlickable { - id: sidebarFlickable - readonly property var rootPane: root - flickableDirection: Flickable.VerticalFlick - contentHeight: sidebarLayout.height - - - StyledScrollBar.vertical: StyledScrollBar { - flickable: sidebarFlickable - } - - ColumnLayout { - id: sidebarLayout - anchors.left: parent.left - anchors.right: parent.right - spacing: Appearance.spacing.small - - readonly property var rootPane: sidebarFlickable.rootPane - - readonly property bool allSectionsExpanded: - themeModeSection.expanded && - colorVariantSection.expanded && - colorSchemeSection.expanded && - animationsSection.expanded && - fontsSection.expanded && - scalesSection.expanded && - transparencySection.expanded && - borderSection.expanded && - backgroundSection.expanded - - RowLayout { - spacing: Appearance.spacing.smaller - - StyledText { - text: qsTr("Appearance") - font.pointSize: Appearance.font.size.large - font.weight: 500 - } - - Item { - Layout.fillWidth: true - } - - IconButton { - icon: sidebarLayout.allSectionsExpanded ? "unfold_less" : "unfold_more" - type: IconButton.Text - label.animate: true - onClicked: { - const shouldExpand = !sidebarLayout.allSectionsExpanded; - themeModeSection.expanded = shouldExpand; - colorVariantSection.expanded = shouldExpand; - colorSchemeSection.expanded = shouldExpand; - animationsSection.expanded = shouldExpand; - fontsSection.expanded = shouldExpand; - scalesSection.expanded = shouldExpand; - transparencySection.expanded = shouldExpand; - borderSection.expanded = shouldExpand; - backgroundSection.expanded = shouldExpand; - } - } - } - - ThemeModeSection { - id: themeModeSection - } - - ColorVariantSection { - id: colorVariantSection - } - - ColorSchemeSection { - id: colorSchemeSection - } - - AnimationsSection { - id: animationsSection - rootPane: sidebarFlickable.rootPane - } - - FontsSection { - id: fontsSection - rootPane: sidebarFlickable.rootPane - } - - ScalesSection { - id: scalesSection - rootPane: sidebarFlickable.rootPane - } - - TransparencySection { - id: transparencySection - rootPane: sidebarFlickable.rootPane - } - - BorderSection { - id: borderSection - rootPane: sidebarFlickable.rootPane - } - - BackgroundSection { - id: backgroundSection - rootPane: sidebarFlickable.rootPane - } - } - } - } - } -} diff --git a/modules/controlcenter/appearance/sections/BackgroundSection.qml b/modules/controlcenter/appearance/sections/BackgroundSection.qml deleted file mode 100644 index d5c16d4..0000000 --- a/modules/controlcenter/appearance/sections/BackgroundSection.qml +++ /dev/null @@ -1,297 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../../components" -import qs.components -import qs.components.controls -import qs.components.containers -import qs.services -import qs.config -import QtQuick -import QtQuick.Layouts - -CollapsibleSection { - id: root - - required property var rootPane - - title: qsTr("Background") - showBackground: true - - SwitchRow { - label: qsTr("Background enabled") - checked: rootPane.backgroundEnabled - onToggled: checked => { - rootPane.backgroundEnabled = checked; - rootPane.saveConfig(); - } - } - - StyledText { - Layout.topMargin: Appearance.spacing.normal - text: qsTr("Desktop Clock") - font.pointSize: Appearance.font.size.larger - font.weight: 500 - } - - SwitchRow { - label: qsTr("Desktop Clock enabled") - checked: rootPane.desktopClockEnabled - onToggled: checked => { - rootPane.desktopClockEnabled = checked; - rootPane.saveConfig(); - } - } - - SectionContainer { - id: posContainer - - contentSpacing: Appearance.spacing.small - z: 1 - - readonly property var pos: (rootPane.desktopClockPosition || "top-left").split('-') - readonly property string currentV: pos[0] - readonly property string currentH: pos[1] - - function updateClockPos(v, h) { - rootPane.desktopClockPosition = v + "-" + h; - rootPane.saveConfig(); - } - - StyledText { - text: qsTr("Positioning") - font.pointSize: Appearance.font.size.larger - font.weight: 500 - } - - SplitButtonRow { - label: qsTr("Vertical Position") - enabled: rootPane.desktopClockEnabled - - menuItems: [ - MenuItem { text: qsTr("Top"); icon: "vertical_align_top"; property string val: "top" }, - MenuItem { text: qsTr("Middle"); icon: "vertical_align_center"; property string val: "middle" }, - MenuItem { text: qsTr("Bottom"); icon: "vertical_align_bottom"; property string val: "bottom" } - ] - - Component.onCompleted: { - for(let i=0; i < menuItems.length; i++) { - if(menuItems[i].val === posContainer.currentV) active = menuItems[i]; - } - } - - // The signal from SplitButtonRow - onSelected: item => posContainer.updateClockPos(item.val, posContainer.currentH) - } - - SplitButtonRow { - label: qsTr("Horizontal Position") - enabled: rootPane.desktopClockEnabled - expandedZ: 99 - - menuItems: [ - MenuItem { text: qsTr("Left"); icon: "align_horizontal_left"; property string val: "left" }, - MenuItem { text: qsTr("Center"); icon: "align_horizontal_center"; property string val: "center" }, - MenuItem { text: qsTr("Right"); icon: "align_horizontal_right"; property string val: "right" } - ] - - Component.onCompleted: { - for(let i=0; i < menuItems.length; i++) { - if(menuItems[i].val === posContainer.currentH) active = menuItems[i]; - } - } - - onSelected: item => posContainer.updateClockPos(posContainer.currentV, item.val) - } - } - - SwitchRow { - label: qsTr("Invert colors") - checked: rootPane.desktopClockInvertColors - onToggled: checked => { - rootPane.desktopClockInvertColors = checked; - rootPane.saveConfig(); - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.small - - StyledText { - text: qsTr("Shadow") - font.pointSize: Appearance.font.size.larger - font.weight: 500 - } - - SwitchRow { - label: qsTr("Enabled") - checked: rootPane.desktopClockShadowEnabled - onToggled: checked => { - rootPane.desktopClockShadowEnabled = checked; - rootPane.saveConfig(); - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - SliderInput { - Layout.fillWidth: true - - label: qsTr("Opacity") - value: rootPane.desktopClockShadowOpacity * 100 - from: 0 - to: 100 - suffix: "%" - validator: IntValidator { bottom: 0; top: 100 } - formatValueFunction: (val) => Math.round(val).toString() - parseValueFunction: (text) => parseInt(text) - - onValueModified: (newValue) => { - rootPane.desktopClockShadowOpacity = newValue / 100; - rootPane.saveConfig(); - } - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - SliderInput { - Layout.fillWidth: true - - label: qsTr("Blur") - value: rootPane.desktopClockShadowBlur * 100 - from: 0 - to: 100 - suffix: "%" - validator: IntValidator { bottom: 0; top: 100 } - formatValueFunction: (val) => Math.round(val).toString() - parseValueFunction: (text) => parseInt(text) - - onValueModified: (newValue) => { - rootPane.desktopClockShadowBlur = newValue / 100; - rootPane.saveConfig(); - } - } - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.small - - StyledText { - text: qsTr("Background") - font.pointSize: Appearance.font.size.larger - font.weight: 500 - } - - SwitchRow { - label: qsTr("Enabled") - checked: rootPane.desktopClockBackgroundEnabled - onToggled: checked => { - rootPane.desktopClockBackgroundEnabled = checked; - rootPane.saveConfig(); - } - } - - SwitchRow { - label: qsTr("Blur enabled") - checked: rootPane.desktopClockBackgroundBlur - onToggled: checked => { - rootPane.desktopClockBackgroundBlur = checked; - rootPane.saveConfig(); - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - SliderInput { - Layout.fillWidth: true - - label: qsTr("Opacity") - value: rootPane.desktopClockBackgroundOpacity * 100 - from: 0 - to: 100 - suffix: "%" - validator: IntValidator { bottom: 0; top: 100 } - formatValueFunction: (val) => Math.round(val).toString() - parseValueFunction: (text) => parseInt(text) - - onValueModified: (newValue) => { - rootPane.desktopClockBackgroundOpacity = newValue / 100; - rootPane.saveConfig(); - } - } - } - } - - - StyledText { - Layout.topMargin: Appearance.spacing.normal - text: qsTr("Visualiser") - font.pointSize: Appearance.font.size.larger - font.weight: 500 - } - - SwitchRow { - label: qsTr("Visualiser enabled") - checked: rootPane.visualiserEnabled - onToggled: checked => { - rootPane.visualiserEnabled = checked; - rootPane.saveConfig(); - } - } - - SwitchRow { - label: qsTr("Visualiser auto hide") - checked: rootPane.visualiserAutoHide - onToggled: checked => { - rootPane.visualiserAutoHide = checked; - rootPane.saveConfig(); - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - SliderInput { - Layout.fillWidth: true - - label: qsTr("Visualiser rounding") - value: rootPane.visualiserRounding - from: 0 - to: 10 - stepSize: 1 - validator: IntValidator { bottom: 0; top: 10 } - formatValueFunction: (val) => Math.round(val).toString() - parseValueFunction: (text) => parseInt(text) - - onValueModified: (newValue) => { - rootPane.visualiserRounding = Math.round(newValue); - rootPane.saveConfig(); - } - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - SliderInput { - Layout.fillWidth: true - - label: qsTr("Visualiser spacing") - value: rootPane.visualiserSpacing - from: 0 - to: 2 - validator: DoubleValidator { bottom: 0; top: 2 } - - onValueModified: (newValue) => { - rootPane.visualiserSpacing = newValue; - rootPane.saveConfig(); - } - } - } -} - diff --git a/modules/controlcenter/appearance/sections/ColorSchemeSection.qml b/modules/controlcenter/appearance/sections/ColorSchemeSection.qml deleted file mode 100644 index 691d908..0000000 --- a/modules/controlcenter/appearance/sections/ColorSchemeSection.qml +++ /dev/null @@ -1,146 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../../../launcher/services" -import qs.components -import qs.components.controls -import qs.components.containers -import qs.services -import qs.config -import Quickshell -import QtQuick -import QtQuick.Layouts - -CollapsibleSection { - title: qsTr("Color scheme") - description: qsTr("Available color schemes") - showBackground: true - - ColumnLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small / 2 - - Repeater { - model: Schemes.list - - delegate: StyledRect { - required property var modelData - - Layout.fillWidth: true - - readonly property string schemeKey: `${modelData.name} ${modelData.flavour}` - readonly property bool isCurrent: schemeKey === Schemes.currentScheme - - color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) - radius: Appearance.rounding.normal - border.width: isCurrent ? 1 : 0 - border.color: Colours.palette.m3primary - - StateLayer { - function onClicked(): void { - const name = modelData.name; - const flavour = modelData.flavour; - const schemeKey = `${name} ${flavour}`; - - Schemes.currentScheme = schemeKey; - Quickshell.execDetached(["caelestia", "scheme", "set", "-n", name, "-f", flavour]); - - Qt.callLater(() => { - reloadTimer.restart(); - }); - } - } - - Timer { - id: reloadTimer - interval: 300 - onTriggered: { - Schemes.reload(); - } - } - - RowLayout { - id: schemeRow - - anchors.fill: parent - anchors.margins: Appearance.padding.normal - - spacing: Appearance.spacing.normal - - StyledRect { - id: preview - - Layout.alignment: Qt.AlignVCenter - - border.width: 1 - border.color: Qt.alpha(`#${modelData.colours?.outline}`, 0.5) - - color: `#${modelData.colours?.surface}` - radius: Appearance.rounding.full - implicitWidth: iconPlaceholder.implicitWidth - implicitHeight: iconPlaceholder.implicitWidth - - MaterialIcon { - id: iconPlaceholder - visible: false - text: "circle" - font.pointSize: Appearance.font.size.large - } - - Item { - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - - implicitWidth: parent.implicitWidth / 2 - clip: true - - StyledRect { - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - - implicitWidth: preview.implicitWidth - color: `#${modelData.colours?.primary}` - radius: Appearance.rounding.full - } - } - } - - Column { - Layout.fillWidth: true - spacing: 0 - - StyledText { - text: modelData.flavour ?? "" - font.pointSize: Appearance.font.size.normal - } - - StyledText { - text: modelData.name ?? "" - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3outline - - elide: Text.ElideRight - anchors.left: parent.left - anchors.right: parent.right - } - } - - Loader { - active: isCurrent - - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large - } - } - } - - implicitHeight: schemeRow.implicitHeight + Appearance.padding.normal * 2 - } - } - } -} - diff --git a/modules/controlcenter/appearance/sections/FontsSection.qml b/modules/controlcenter/appearance/sections/FontsSection.qml deleted file mode 100644 index ef807b1..0000000 --- a/modules/controlcenter/appearance/sections/FontsSection.qml +++ /dev/null @@ -1,280 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../../components" -import qs.components -import qs.components.controls -import qs.components.containers -import qs.services -import qs.config -import QtQuick -import QtQuick.Layouts - -CollapsibleSection { - id: root - - required property var rootPane - - title: qsTr("Fonts") - showBackground: true - - CollapsibleSection { - id: materialFontSection - title: qsTr("Material font family") - expanded: true - showBackground: true - nested: true - - Loader { - id: materialFontLoader - Layout.fillWidth: true - Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 - active: materialFontSection.expanded - - sourceComponent: StyledListView { - id: materialFontList - property alias contentHeight: materialFontList.contentHeight - - clip: true - spacing: Appearance.spacing.small / 2 - model: Qt.fontFamilies() - - StyledScrollBar.vertical: StyledScrollBar { - flickable: materialFontList - } - - delegate: StyledRect { - required property string modelData - required property int index - - width: ListView.view.width - - readonly property bool isCurrent: modelData === rootPane.fontFamilyMaterial - color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) - radius: Appearance.rounding.normal - border.width: isCurrent ? 1 : 0 - border.color: Colours.palette.m3primary - - StateLayer { - function onClicked(): void { - rootPane.fontFamilyMaterial = modelData; - rootPane.saveConfig(); - } - } - - RowLayout { - id: fontFamilyMaterialRow - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal - - spacing: Appearance.spacing.normal - - StyledText { - text: modelData - font.pointSize: Appearance.font.size.normal - } - - Item { - Layout.fillWidth: true - } - - Loader { - active: isCurrent - - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large - } - } - } - - implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2 - } - } - } - } - - CollapsibleSection { - id: monoFontSection - title: qsTr("Monospace font family") - expanded: false - showBackground: true - nested: true - - Loader { - Layout.fillWidth: true - Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 - active: monoFontSection.expanded - - sourceComponent: StyledListView { - id: monoFontList - property alias contentHeight: monoFontList.contentHeight - - clip: true - spacing: Appearance.spacing.small / 2 - model: Qt.fontFamilies() - - StyledScrollBar.vertical: StyledScrollBar { - flickable: monoFontList - } - - delegate: StyledRect { - required property string modelData - required property int index - - width: ListView.view.width - - readonly property bool isCurrent: modelData === rootPane.fontFamilyMono - color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) - radius: Appearance.rounding.normal - border.width: isCurrent ? 1 : 0 - border.color: Colours.palette.m3primary - - StateLayer { - function onClicked(): void { - rootPane.fontFamilyMono = modelData; - rootPane.saveConfig(); - } - } - - RowLayout { - id: fontFamilyMonoRow - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal - - spacing: Appearance.spacing.normal - - StyledText { - text: modelData - font.pointSize: Appearance.font.size.normal - } - - Item { - Layout.fillWidth: true - } - - Loader { - active: isCurrent - - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large - } - } - } - - implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2 - } - } - } - } - - CollapsibleSection { - id: sansFontSection - title: qsTr("Sans-serif font family") - expanded: false - showBackground: true - nested: true - - Loader { - Layout.fillWidth: true - Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 - active: sansFontSection.expanded - - sourceComponent: StyledListView { - id: sansFontList - property alias contentHeight: sansFontList.contentHeight - - clip: true - spacing: Appearance.spacing.small / 2 - model: Qt.fontFamilies() - - StyledScrollBar.vertical: StyledScrollBar { - flickable: sansFontList - } - - delegate: StyledRect { - required property string modelData - required property int index - - width: ListView.view.width - - readonly property bool isCurrent: modelData === rootPane.fontFamilySans - color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) - radius: Appearance.rounding.normal - border.width: isCurrent ? 1 : 0 - border.color: Colours.palette.m3primary - - StateLayer { - function onClicked(): void { - rootPane.fontFamilySans = modelData; - rootPane.saveConfig(); - } - } - - RowLayout { - id: fontFamilySansRow - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal - - spacing: Appearance.spacing.normal - - StyledText { - text: modelData - font.pointSize: Appearance.font.size.normal - } - - Item { - Layout.fillWidth: true - } - - Loader { - active: isCurrent - - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large - } - } - } - - implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2 - } - } - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - SliderInput { - Layout.fillWidth: true - - label: qsTr("Font size scale") - value: rootPane.fontSizeScale - from: 0.7 - to: 1.5 - decimals: 2 - suffix: "×" - validator: DoubleValidator { bottom: 0.7; top: 1.5 } - - onValueModified: (newValue) => { - rootPane.fontSizeScale = newValue; - rootPane.saveConfig(); - } - } - } -} - diff --git a/modules/controlcenter/launcher/LauncherPane.qml b/modules/controlcenter/launcher/LauncherPane.qml deleted file mode 100644 index fabe75e..0000000 --- a/modules/controlcenter/launcher/LauncherPane.qml +++ /dev/null @@ -1,597 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../components" -import "../../launcher/services" -import qs.components -import qs.components.controls -import qs.components.effects -import qs.components.containers -import qs.services -import qs.config -import qs.utils -import Caelestia -import Quickshell -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts -import "../../../utils/scripts/fuzzysort.js" as Fuzzy - -Item { - id: root - - required property Session session - - property var selectedApp: root.session.launcher.active - property bool hideFromLauncherChecked: false - - anchors.fill: parent - - onSelectedAppChanged: { - root.session.launcher.active = root.selectedApp; - updateToggleState(); - } - - Connections { - target: root.session.launcher - function onActiveChanged() { - root.selectedApp = root.session.launcher.active; - updateToggleState(); - } - } - - function updateToggleState() { - if (!root.selectedApp) { - root.hideFromLauncherChecked = false; - return; - } - - const appId = root.selectedApp.id || root.selectedApp.entry?.id; - - if (Config.launcher.hiddenApps && Config.launcher.hiddenApps.length > 0) { - root.hideFromLauncherChecked = Config.launcher.hiddenApps.includes(appId); - } else { - root.hideFromLauncherChecked = false; - } - } - - function saveHiddenApps(isHidden) { - if (!root.selectedApp) { - return; - } - - const appId = root.selectedApp.id || root.selectedApp.entry?.id; - - const hiddenApps = Config.launcher.hiddenApps ? [...Config.launcher.hiddenApps] : []; - - if (isHidden) { - if (!hiddenApps.includes(appId)) { - hiddenApps.push(appId); - } - } else { - const index = hiddenApps.indexOf(appId); - if (index !== -1) { - hiddenApps.splice(index, 1); - } - } - - Config.launcher.hiddenApps = hiddenApps; - Config.save(); - } - - - AppDb { - id: allAppsDb - - path: `${Paths.state}/apps.sqlite` - entries: DesktopEntries.applications.values - } - - property string searchText: "" - - function filterApps(search: string): list<var> { - if (!search || search.trim() === "") { - const apps = []; - for (let i = 0; i < allAppsDb.apps.length; i++) { - apps.push(allAppsDb.apps[i]); - } - return apps; - } - - if (!allAppsDb.apps || allAppsDb.apps.length === 0) { - return []; - } - - const preparedApps = []; - for (let i = 0; i < allAppsDb.apps.length; i++) { - const app = allAppsDb.apps[i]; - const name = app.name || app.entry?.name || ""; - preparedApps.push({ - _item: app, - name: Fuzzy.prepare(name) - }); - } - - const results = Fuzzy.go(search, preparedApps, { - all: true, - keys: ["name"], - scoreFn: r => r[0].score - }); - - return results - .sort((a, b) => b._score - a._score) - .map(r => r.obj._item); - } - - property list<var> filteredApps: [] - - function updateFilteredApps() { - filteredApps = filterApps(searchText); - } - - onSearchTextChanged: { - updateFilteredApps(); - } - - Component.onCompleted: { - updateFilteredApps(); - } - - Connections { - target: allAppsDb - function onAppsChanged() { - updateFilteredApps(); - } - } - - SplitPaneLayout { - anchors.fill: parent - - leftContent: Component { - - ColumnLayout { - id: leftLauncherLayout - anchors.fill: parent - - spacing: Appearance.spacing.small - - RowLayout { - spacing: Appearance.spacing.smaller - - StyledText { - text: qsTr("Launcher") - font.pointSize: Appearance.font.size.large - font.weight: 500 - } - - Item { - Layout.fillWidth: true - } - - ToggleButton { - toggled: !root.session.launcher.active - icon: "settings" - accent: "Primary" - iconSize: Appearance.font.size.normal - horizontalPadding: Appearance.padding.normal - verticalPadding: Appearance.padding.smaller - tooltip: qsTr("Launcher settings") - - onClicked: { - if (root.session.launcher.active) { - root.session.launcher.active = null; - } else { - if (root.filteredApps.length > 0) { - root.session.launcher.active = root.filteredApps[0]; - } - } - } - } - } - - StyledText { - Layout.topMargin: Appearance.spacing.large - text: qsTr("Applications (%1)").arg(root.searchText ? root.filteredApps.length : allAppsDb.apps.length) - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - StyledText { - text: qsTr("All applications available in the launcher") - color: Colours.palette.m3outline - } - - StyledRect { - Layout.fillWidth: true - Layout.topMargin: Appearance.spacing.normal - Layout.bottomMargin: Appearance.spacing.small - - color: Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.full - - implicitHeight: Math.max(searchIcon.implicitHeight, searchField.implicitHeight, clearIcon.implicitHeight) - - MaterialIcon { - id: searchIcon - - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Appearance.padding.normal - - text: "search" - color: Colours.palette.m3onSurfaceVariant - } - - StyledTextField { - id: searchField - - anchors.left: searchIcon.right - anchors.right: clearIcon.left - anchors.leftMargin: Appearance.spacing.small - anchors.rightMargin: Appearance.spacing.small - - topPadding: Appearance.padding.normal - bottomPadding: Appearance.padding.normal - - placeholderText: qsTr("Search applications...") - - onTextChanged: { - root.searchText = text; - } - } - - MaterialIcon { - id: clearIcon - - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: Appearance.padding.normal - - width: searchField.text ? implicitWidth : implicitWidth / 2 - opacity: { - if (!searchField.text) - return 0; - if (clearMouse.pressed) - return 0.7; - if (clearMouse.containsMouse) - return 0.8; - return 1; - } - - text: "close" - color: Colours.palette.m3onSurfaceVariant - - MouseArea { - id: clearMouse - - anchors.fill: parent - hoverEnabled: true - cursorShape: searchField.text ? Qt.PointingHandCursor : undefined - - onClicked: searchField.text = "" - } - - Behavior on width { - Anim { - duration: Appearance.anim.durations.small - } - } - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.small - } - } - } - } - - Loader { - id: appsListLoader - Layout.fillWidth: true - Layout.fillHeight: true - active: true - - sourceComponent: StyledListView { - id: appsListView - - Layout.fillWidth: true - Layout.fillHeight: true - - model: root.filteredApps - spacing: Appearance.spacing.small / 2 - clip: true - - StyledScrollBar.vertical: StyledScrollBar { - flickable: parent - } - - delegate: StyledRect { - required property var modelData - - width: parent ? parent.width : 0 - - readonly property bool isSelected: root.selectedApp === modelData - - color: isSelected ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent" - radius: Appearance.rounding.normal - - opacity: 0 - - Behavior on opacity { - NumberAnimation { - duration: 1000 - easing.type: Easing.OutCubic - } - } - - Component.onCompleted: { - opacity = 1; - } - - StateLayer { - function onClicked(): void { - root.session.launcher.active = modelData; - } - } - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal - - spacing: Appearance.spacing.normal - - IconImage { - Layout.alignment: Qt.AlignVCenter - implicitSize: 32 - source: { - const entry = modelData.entry; - return entry ? Quickshell.iconPath(entry.icon, "image-missing") : "image-missing"; - } - } - - StyledText { - Layout.fillWidth: true - text: modelData.name || modelData.entry?.name || qsTr("Unknown") - font.pointSize: Appearance.font.size.normal - } - } - - implicitHeight: 40 - } - } - } - } - } - - rightContent: Component { - Item { - id: rightLauncherPane - - property var pane: root.session.launcher.active - property string paneId: pane ? (pane.id || pane.entry?.id || "") : "" - property Component targetComponent: settings - property Component nextComponent: settings - property var displayedApp: null - - function getComponentForPane() { - return pane ? appDetails : settings; - } - - Component.onCompleted: { - displayedApp = pane; - targetComponent = getComponentForPane(); - nextComponent = targetComponent; - } - - Loader { - id: rightLauncherLoader - - anchors.fill: parent - - opacity: 1 - scale: 1 - transformOrigin: Item.Center - clip: false - - sourceComponent: rightLauncherPane.targetComponent - active: true - - property var displayedApp: rightLauncherPane.displayedApp - - onItemChanged: { - if (item && rightLauncherPane.pane && rightLauncherPane.displayedApp !== rightLauncherPane.pane) { - rightLauncherPane.displayedApp = rightLauncherPane.pane; - } - } - } - - Behavior on paneId { - PaneTransition { - target: rightLauncherLoader - propertyActions: [ - PropertyAction { - target: rightLauncherPane - property: "displayedApp" - value: rightLauncherPane.pane - }, - PropertyAction { - target: rightLauncherLoader - property: "active" - value: false - }, - PropertyAction { - target: rightLauncherPane - property: "targetComponent" - value: rightLauncherPane.nextComponent - }, - PropertyAction { - target: rightLauncherLoader - property: "active" - value: true - } - ] - } - } - - onPaneChanged: { - nextComponent = getComponentForPane(); - paneId = pane ? (pane.id || pane.entry?.id || "") : ""; - } - - onDisplayedAppChanged: { - if (displayedApp) { - const appId = displayedApp.id || displayedApp.entry?.id; - if (Config.launcher.hiddenApps && Config.launcher.hiddenApps.length > 0) { - root.hideFromLauncherChecked = Config.launcher.hiddenApps.includes(appId); - } else { - root.hideFromLauncherChecked = false; - } - } else { - root.hideFromLauncherChecked = false; - } - } - } - } - } - - Component { - id: settings - - StyledFlickable { - id: settingsFlickable - flickableDirection: Flickable.VerticalFlick - contentHeight: settingsInner.height - - StyledScrollBar.vertical: StyledScrollBar { - flickable: settingsFlickable - } - - Settings { - id: settingsInner - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - session: root.session - } - } - } - - Component { - id: appDetails - - ColumnLayout { - id: appDetailsLayout - anchors.fill: parent - - readonly property var displayedApp: parent && parent.displayedApp !== undefined ? parent.displayedApp : null - - spacing: Appearance.spacing.normal - - SettingsHeader { - Layout.leftMargin: Appearance.padding.large * 2 - Layout.rightMargin: Appearance.padding.large * 2 - Layout.topMargin: Appearance.padding.large * 2 - visible: displayedApp === null - icon: "apps" - title: qsTr("Launcher Applications") - } - - Item { - Layout.alignment: Qt.AlignHCenter - Layout.leftMargin: Appearance.padding.large * 2 - Layout.rightMargin: Appearance.padding.large * 2 - Layout.topMargin: Appearance.padding.large * 2 - visible: displayedApp !== null - implicitWidth: Math.max(appIconImage.implicitWidth, appTitleText.implicitWidth) - implicitHeight: appIconImage.implicitHeight + Appearance.spacing.normal + appTitleText.implicitHeight - - ColumnLayout { - anchors.centerIn: parent - spacing: Appearance.spacing.normal - - IconImage { - id: appIconImage - Layout.alignment: Qt.AlignHCenter - implicitSize: Appearance.font.size.extraLarge * 3 * 2 - source: { - const app = appDetailsLayout.displayedApp; - if (!app) return "image-missing"; - const entry = app.entry; - if (entry && entry.icon) { - return Quickshell.iconPath(entry.icon, "image-missing"); - } - return "image-missing"; - } - } - - StyledText { - id: appTitleText - Layout.alignment: Qt.AlignHCenter - text: displayedApp ? (displayedApp.name || displayedApp.entry?.name || qsTr("Application Details")) : "" - font.pointSize: Appearance.font.size.large - font.bold: true - } - } - } - - Item { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.topMargin: Appearance.spacing.large - Layout.leftMargin: Appearance.padding.large * 2 - Layout.rightMargin: Appearance.padding.large * 2 - - StyledFlickable { - id: detailsFlickable - anchors.fill: parent - flickableDirection: Flickable.VerticalFlick - contentHeight: debugLayout.height - - StyledScrollBar.vertical: StyledScrollBar { - flickable: parent - } - - ColumnLayout { - id: debugLayout - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - spacing: Appearance.spacing.normal - - SwitchRow { - Layout.topMargin: Appearance.spacing.normal - visible: appDetailsLayout.displayedApp !== null - label: qsTr("Hide from launcher") - checked: root.hideFromLauncherChecked - enabled: appDetailsLayout.displayedApp !== null - onToggled: checked => { - root.hideFromLauncherChecked = checked; - const app = appDetailsLayout.displayedApp; - if (app) { - const appId = app.id || app.entry?.id; - const hiddenApps = Config.launcher.hiddenApps ? [...Config.launcher.hiddenApps] : []; - if (checked) { - if (!hiddenApps.includes(appId)) { - hiddenApps.push(appId); - } - } else { - const index = hiddenApps.indexOf(appId); - if (index !== -1) { - hiddenApps.splice(index, 1); - } - } - Config.launcher.hiddenApps = hiddenApps; - Config.save(); - } - } - } - - } - } - } - } - } -} diff --git a/modules/controlcenter/network/NetworkSettings.qml b/modules/controlcenter/network/NetworkSettings.qml index 04746af..81175fb 100644 --- a/modules/controlcenter/network/NetworkSettings.qml +++ b/modules/controlcenter/network/NetworkSettings.qml @@ -63,45 +63,6 @@ ColumnLayout { SectionHeader { Layout.topMargin: Appearance.spacing.large - title: qsTr("VPN") - description: qsTr("VPN provider settings") - visible: Config.utilities.vpn.enabled || Config.utilities.vpn.provider.length > 0 - } - - SectionContainer { - visible: Config.utilities.vpn.enabled || Config.utilities.vpn.provider.length > 0 - - ToggleRow { - label: qsTr("VPN enabled") - checked: Config.utilities.vpn.enabled - toggle.onToggled: { - Config.utilities.vpn.enabled = checked; - Config.save(); - } - } - - PropertyRow { - showTopMargin: true - label: qsTr("Providers") - value: qsTr("%1").arg(Config.utilities.vpn.provider.length) - } - - TextButton { - Layout.fillWidth: true - Layout.topMargin: Appearance.spacing.normal - Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 - text: qsTr("⚙ Manage VPN Providers") - inactiveColour: Colours.palette.m3secondaryContainer - inactiveOnColour: Colours.palette.m3onSecondaryContainer - - onClicked: { - vpnSettingsDialog.open(); - } - } - } - - SectionHeader { - Layout.topMargin: Appearance.spacing.large title: qsTr("Current connection") description: qsTr("Active network connection information") } @@ -135,38 +96,5 @@ ColumnLayout { value: Nmcli.active ? qsTr("%1 MHz").arg(Nmcli.active.frequency) : qsTr("N/A") } } - - Popup { - id: vpnSettingsDialog - - parent: Overlay.overlay - anchors.centerIn: parent - width: Math.min(600, parent.width - Appearance.padding.large * 2) - height: Math.min(700, parent.height - Appearance.padding.large * 2) - - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: StyledRect { - color: Colours.palette.m3surface - radius: Appearance.rounding.large - } - - StyledFlickable { - anchors.fill: parent - anchors.margins: Appearance.padding.large * 1.5 - flickableDirection: Flickable.VerticalFlick - contentHeight: vpnSettingsContent.height - clip: true - - VpnSettings { - id: vpnSettingsContent - - anchors.left: parent.left - anchors.right: parent.right - session: root.session - } - } - } } diff --git a/modules/controlcenter/network/NetworkingPane.qml b/modules/controlcenter/network/NetworkingPane.qml index 23e795e..9047174 100644 --- a/modules/controlcenter/network/NetworkingPane.qml +++ b/modules/controlcenter/network/NetworkingPane.qml @@ -112,24 +112,6 @@ Item { } CollapsibleSection { - id: vpnListSection - - Layout.fillWidth: true - title: qsTr("VPN") - expanded: true - - Loader { - Layout.fillWidth: true - sourceComponent: Component { - VpnList { - session: root.session - showHeader: false - } - } - } - } - - CollapsibleSection { id: ethernetListSection Layout.fillWidth: true @@ -171,17 +153,15 @@ Item { rightContent: Component { Item { id: rightPaneItem - - property var vpnPane: root.session && root.session.vpn ? root.session.vpn.active : null + property var ethernetPane: root.session && root.session.ethernet ? root.session.ethernet.active : null property var wirelessPane: root.session && root.session.network ? root.session.network.active : null - property var pane: vpnPane || ethernetPane || wirelessPane - property string paneId: vpnPane ? ("vpn:" + (vpnPane.name || "")) : (ethernetPane ? ("eth:" + (ethernetPane.interface || "")) : (wirelessPane ? ("wifi:" + (wirelessPane.ssid || wirelessPane.bssid || "")) : "settings")) + property var pane: ethernetPane || wirelessPane + property string paneId: ethernetPane ? ("eth:" + (ethernetPane.interface || "")) : (wirelessPane ? ("wifi:" + (wirelessPane.ssid || wirelessPane.bssid || "")) : "settings") property Component targetComponent: settingsComponent property Component nextComponent: settingsComponent function getComponentForPane() { - if (vpnPane) return vpnDetailsComponent; if (ethernetPane) return ethernetDetailsComponent; if (wirelessPane) return wirelessDetailsComponent; return settingsComponent; @@ -193,27 +173,12 @@ Item { } Connections { - target: root.session && root.session.vpn ? root.session.vpn : null - enabled: target !== null - - function onActiveChanged() { - // Clear others when VPN is selected - if (root.session && root.session.vpn && root.session.vpn.active) { - if (root.session.ethernet && root.session.ethernet.active) root.session.ethernet.active = null; - if (root.session.network && root.session.network.active) root.session.network.active = null; - } - rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); - } - } - - Connections { target: root.session && root.session.ethernet ? root.session.ethernet : null enabled: target !== null - + function onActiveChanged() { // Clear others when ethernet is selected if (root.session && root.session.ethernet && root.session.ethernet.active) { - if (root.session.vpn && root.session.vpn.active) root.session.vpn.active = null; if (root.session.network && root.session.network.active) root.session.network.active = null; } rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); @@ -223,11 +188,10 @@ Item { Connections { target: root.session && root.session.network ? root.session.network : null enabled: target !== null - + function onActiveChanged() { // Clear others when wireless is selected if (root.session && root.session.network && root.session.network.active) { - if (root.session.vpn && root.session.vpn.active) root.session.vpn.active = null; if (root.session.ethernet && root.session.ethernet.active) root.session.ethernet.active = null; } rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); @@ -333,29 +297,6 @@ Item { } } - Component { - id: vpnDetailsComponent - - StyledFlickable { - id: vpnFlickable - flickableDirection: Flickable.VerticalFlick - contentHeight: vpnDetailsInner.height - - StyledScrollBar.vertical: StyledScrollBar { - flickable: vpnFlickable - } - - VpnDetails { - id: vpnDetailsInner - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - session: root.session - } - } - } - WirelessPasswordDialog { anchors.fill: parent session: root.session diff --git a/modules/controlcenter/network/VpnDetails.qml b/modules/controlcenter/network/VpnDetails.qml deleted file mode 100644 index 76a9b17..0000000 --- a/modules/controlcenter/network/VpnDetails.qml +++ /dev/null @@ -1,367 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../components" -import qs.components -import qs.components.controls -import qs.components.effects -import qs.components.containers -import qs.services -import qs.config -import qs.utils -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - -DeviceDetails { - id: root - - required property Session session - readonly property var vpnProvider: root.session.vpn.active - readonly property bool providerEnabled: { - if (!vpnProvider || vpnProvider.index === undefined) return false; - const provider = Config.utilities.vpn.provider[vpnProvider.index]; - return provider && typeof provider === "object" && provider.enabled === true; - } - - device: vpnProvider - - headerComponent: Component { - ConnectionHeader { - icon: "vpn_key" - title: root.vpnProvider?.displayName ?? qsTr("Unknown") - } - } - - sections: [ - Component { - ColumnLayout { - spacing: Appearance.spacing.normal - - SectionHeader { - title: qsTr("Connection status") - description: qsTr("VPN connection settings") - } - - SectionContainer { - ToggleRow { - label: qsTr("Enable this provider") - checked: root.providerEnabled - toggle.onToggled: { - if (!root.vpnProvider) return; - const providers = []; - const index = root.vpnProvider.index; - - // Copy providers and update enabled state - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - const p = Config.utilities.vpn.provider[i]; - if (typeof p === "object") { - const newProvider = { - name: p.name, - displayName: p.displayName, - interface: p.interface - }; - - if (checked) { - // Enable this one, disable others - newProvider.enabled = (i === index); - } else { - // Just disable this one - newProvider.enabled = (i === index) ? false : (p.enabled !== false); - } - - providers.push(newProvider); - } else { - providers.push(p); - } - } - - Config.utilities.vpn.provider = providers; - Config.save(); - } - } - - RowLayout { - Layout.fillWidth: true - Layout.topMargin: Appearance.spacing.normal - spacing: Appearance.spacing.normal - - TextButton { - Layout.fillWidth: true - Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 - visible: root.providerEnabled - enabled: !VPN.connecting - inactiveColour: Colours.palette.m3primaryContainer - inactiveOnColour: Colours.palette.m3onPrimaryContainer - text: VPN.connected ? qsTr("Disconnect") : qsTr("Connect") - - onClicked: { - VPN.toggle(); - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("Edit Provider") - inactiveColour: Colours.palette.m3secondaryContainer - inactiveOnColour: Colours.palette.m3onSecondaryContainer - - onClicked: { - editVpnDialog.editIndex = root.vpnProvider.index; - editVpnDialog.providerName = root.vpnProvider.name; - editVpnDialog.displayName = root.vpnProvider.displayName; - editVpnDialog.interfaceName = root.vpnProvider.interface; - editVpnDialog.open(); - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("Delete Provider") - inactiveColour: Colours.palette.m3errorContainer - inactiveOnColour: Colours.palette.m3onErrorContainer - - onClicked: { - const providers = []; - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - if (i !== root.vpnProvider.index) { - providers.push(Config.utilities.vpn.provider[i]); - } - } - Config.utilities.vpn.provider = providers; - Config.save(); - root.session.vpn.active = null; - } - } - } - } - } - }, - Component { - ColumnLayout { - spacing: Appearance.spacing.normal - - SectionHeader { - title: qsTr("Provider details") - description: qsTr("VPN provider information") - } - - SectionContainer { - contentSpacing: Appearance.spacing.small / 2 - - PropertyRow { - label: qsTr("Provider") - value: root.vpnProvider?.name ?? qsTr("Unknown") - } - - PropertyRow { - showTopMargin: true - label: qsTr("Display name") - value: root.vpnProvider?.displayName ?? qsTr("Unknown") - } - - PropertyRow { - showTopMargin: true - label: qsTr("Interface") - value: root.vpnProvider?.interface || qsTr("N/A") - } - - PropertyRow { - showTopMargin: true - label: qsTr("Status") - value: { - if (!root.providerEnabled) return qsTr("Disabled"); - if (VPN.connecting) return qsTr("Connecting..."); - if (VPN.connected) return qsTr("Connected"); - return qsTr("Enabled (Not connected)"); - } - } - - PropertyRow { - showTopMargin: true - label: qsTr("Enabled") - value: root.providerEnabled ? qsTr("Yes") : qsTr("No") - } - } - } - } - ] - - // Edit VPN Dialog - Popup { - id: editVpnDialog - - property int editIndex: -1 - property string providerName: "" - property string displayName: "" - property string interfaceName: "" - - parent: Overlay.overlay - anchors.centerIn: parent - width: Math.min(400, parent.width - Appearance.padding.large * 2) - padding: Appearance.padding.large * 1.5 - - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - opacity: 0 - scale: 0.7 - - enter: Transition { - ParallelAnimation { - NumberAnimation { property: "opacity"; from: 0; to: 1; duration: Appearance.anim.durations.expressiveFastSpatial; easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial } - NumberAnimation { property: "scale"; from: 0.7; to: 1; duration: Appearance.anim.durations.expressiveFastSpatial; easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial } - } - } - - exit: Transition { - ParallelAnimation { - NumberAnimation { property: "opacity"; from: 1; to: 0; duration: Appearance.anim.durations.expressiveFastSpatial; easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial } - NumberAnimation { property: "scale"; from: 1; to: 0.7; duration: Appearance.anim.durations.expressiveFastSpatial; easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial } - } - } - - function closeWithAnimation(): void { - close(); - } - - Overlay.modal: Rectangle { - color: Qt.rgba(0, 0, 0, 0.4 * editVpnDialog.opacity) - } - - - background: StyledRect { - color: Colours.palette.m3surfaceContainerHigh - radius: Appearance.rounding.large - - layer.enabled: true - layer.effect: DropShadow { - color: Qt.rgba(0, 0, 0, 0.3) - radius: 16 - samples: 33 - verticalOffset: 4 - } - } - - contentItem: ColumnLayout { - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Edit VPN Provider") - font.pointSize: Appearance.font.size.large - font.weight: 500 - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.smaller / 2 - - StyledText { - text: qsTr("Display Name") - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3onSurfaceVariant - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: 40 - color: displayNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: displayNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - StyledTextField { - id: displayNameField - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignLeft - text: editVpnDialog.displayName - onTextChanged: editVpnDialog.displayName = text - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.smaller / 2 - - StyledText { - text: qsTr("Interface (e.g., wg0, torguard)") - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3onSurfaceVariant - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: 40 - color: interfaceNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: interfaceNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - StyledTextField { - id: interfaceNameField - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignLeft - text: editVpnDialog.interfaceName - onTextChanged: editVpnDialog.interfaceName = text - } - } - } - - Item { Layout.preferredHeight: Appearance.spacing.normal } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.normal - - TextButton { - Layout.fillWidth: true - text: qsTr("Cancel") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - onClicked: editVpnDialog.closeWithAnimation() - } - - TextButton { - Layout.fillWidth: true - text: qsTr("Save") - enabled: editVpnDialog.interfaceName.length > 0 - inactiveColour: Colours.palette.m3primaryContainer - inactiveOnColour: Colours.palette.m3onPrimaryContainer - - onClicked: { - const providers = []; - const oldProvider = Config.utilities.vpn.provider[editVpnDialog.editIndex]; - const wasEnabled = typeof oldProvider === "object" ? (oldProvider.enabled !== false) : true; - - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - if (i === editVpnDialog.editIndex) { - providers.push({ - name: editVpnDialog.providerName, - displayName: editVpnDialog.displayName || editVpnDialog.interfaceName, - interface: editVpnDialog.interfaceName, - enabled: wasEnabled - }); - } else { - providers.push(Config.utilities.vpn.provider[i]); - } - } - - Config.utilities.vpn.provider = providers; - Config.save(); - editVpnDialog.closeWithAnimation(); - } - } - } - } - } -} diff --git a/modules/controlcenter/network/VpnList.qml b/modules/controlcenter/network/VpnList.qml deleted file mode 100644 index 665f8cc..0000000 --- a/modules/controlcenter/network/VpnList.qml +++ /dev/null @@ -1,646 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import qs.components -import qs.components.controls -import qs.components.containers -import qs.components.effects -import qs.services -import qs.config -import qs.utils -import Quickshell -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - -ColumnLayout { - id: root - - required property Session session - property bool showHeader: true - property int pendingSwitchIndex: -1 - - spacing: Appearance.spacing.normal - - Connections { - target: VPN - function onConnectedChanged() { - if (!VPN.connected && root.pendingSwitchIndex >= 0) { - const targetIndex = root.pendingSwitchIndex; - root.pendingSwitchIndex = -1; - - const providers = []; - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - const p = Config.utilities.vpn.provider[i]; - if (typeof p === "object") { - const newProvider = { - name: p.name, - displayName: p.displayName, - interface: p.interface, - enabled: (i === targetIndex) - }; - providers.push(newProvider); - } else { - providers.push(p); - } - } - Config.utilities.vpn.provider = providers; - Config.save(); - - Qt.callLater(function() { - VPN.toggle(); - }); - } - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("+ Add VPN Provider") - inactiveColour: Colours.palette.m3primaryContainer - inactiveOnColour: Colours.palette.m3onPrimaryContainer - - onClicked: { - vpnDialog.showProviderSelection(); - } - } - - ListView { - id: listView - - Layout.fillWidth: true - Layout.preferredHeight: contentHeight - - interactive: false - spacing: Appearance.spacing.smaller - - model: ScriptModel { - values: Config.utilities.vpn.provider.map((provider, index) => { - const isObject = typeof provider === "object"; - const name = isObject ? (provider.name || "custom") : String(provider); - const displayName = isObject ? (provider.displayName || name) : name; - const iface = isObject ? (provider.interface || "") : ""; - const enabled = isObject ? (provider.enabled === true) : false; - - return { - index: index, - name: name, - displayName: displayName, - interface: iface, - provider: provider, - enabled: enabled - }; - }) - } - - delegate: Component { - StyledRect { - required property var modelData - required property int index - - width: ListView.view ? ListView.view.width : undefined - - color: Qt.alpha(Colours.tPalette.m3surfaceContainer, (root.session && root.session.vpn && root.session.vpn.active === modelData) ? Colours.tPalette.m3surfaceContainer.a : 0) - radius: Appearance.rounding.normal - - StateLayer { - function onClicked(): void { - if (root.session && root.session.vpn) { - root.session.vpn.active = modelData; - } - } - } - - RowLayout { - id: rowLayout - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal - - spacing: Appearance.spacing.normal - - StyledRect { - implicitWidth: implicitHeight - implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 - - radius: Appearance.rounding.normal - color: modelData.enabled && VPN.connected ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh - - MaterialIcon { - id: icon - - anchors.centerIn: parent - text: modelData.enabled && VPN.connected ? "vpn_key" : "vpn_key_off" - font.pointSize: Appearance.font.size.large - fill: modelData.enabled && VPN.connected ? 1 : 0 - color: modelData.enabled && VPN.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface - } - } - - ColumnLayout { - Layout.fillWidth: true - - spacing: 0 - - StyledText { - Layout.fillWidth: true - elide: Text.ElideRight - maximumLineCount: 1 - - text: modelData.displayName || qsTr("Unknown") - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.smaller - - StyledText { - Layout.fillWidth: true - text: { - if (modelData.enabled && VPN.connected) return qsTr("Connected"); - if (modelData.enabled && VPN.connecting) return qsTr("Connecting..."); - if (modelData.enabled) return qsTr("Enabled"); - return qsTr("Disabled"); - } - color: modelData.enabled ? (VPN.connected ? Colours.palette.m3primary : Colours.palette.m3onSurface) : Colours.palette.m3outline - font.pointSize: Appearance.font.size.small - font.weight: modelData.enabled && VPN.connected ? 500 : 400 - elide: Text.ElideRight - } - } - } - - StyledRect { - implicitWidth: implicitHeight - implicitHeight: connectIcon.implicitHeight + Appearance.padding.smaller * 2 - - radius: Appearance.rounding.full - color: Qt.alpha(Colours.palette.m3primaryContainer, VPN.connected && modelData.enabled ? 1 : 0) - - StateLayer { - enabled: !VPN.connecting - function onClicked(): void { - const clickedIndex = modelData.index; - - if (modelData.enabled) { - VPN.toggle(); - } else { - if (VPN.connected) { - root.pendingSwitchIndex = clickedIndex; - VPN.toggle(); - } else { - const providers = []; - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - const p = Config.utilities.vpn.provider[i]; - if (typeof p === "object") { - const newProvider = { - name: p.name, - displayName: p.displayName, - interface: p.interface, - enabled: (i === clickedIndex) - }; - providers.push(newProvider); - } else { - providers.push(p); - } - } - Config.utilities.vpn.provider = providers; - Config.save(); - - Qt.callLater(function() { - VPN.toggle(); - }); - } - } - } - } - - MaterialIcon { - id: connectIcon - - anchors.centerIn: parent - text: VPN.connected && modelData.enabled ? "link_off" : "link" - color: VPN.connected && modelData.enabled ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface - } - } - - StyledRect { - implicitWidth: implicitHeight - implicitHeight: deleteIcon.implicitHeight + Appearance.padding.smaller * 2 - - radius: Appearance.rounding.full - color: "transparent" - - StateLayer { - function onClicked(): void { - const providers = []; - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - if (i !== modelData.index) { - providers.push(Config.utilities.vpn.provider[i]); - } - } - Config.utilities.vpn.provider = providers; - Config.save(); - } - } - - MaterialIcon { - id: deleteIcon - - anchors.centerIn: parent - text: "delete" - color: Colours.palette.m3onSurface - } - } - } - - implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2 - } - } - } - - Popup { - id: vpnDialog - - property string currentState: "selection" - property int editIndex: -1 - property string providerName: "" - property string displayName: "" - property string interfaceName: "" - - parent: Overlay.overlay - x: Math.round((parent.width - width) / 2) - y: Math.round((parent.height - height) / 2) - implicitWidth: Math.min(400, parent.width - Appearance.padding.large * 2) - padding: Appearance.padding.large * 1.5 - - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - opacity: 0 - scale: 0.7 - - enter: Transition { - ParallelAnimation { - NumberAnimation { property: "opacity"; from: 0; to: 1; duration: Appearance.anim.durations.normal; easing.bezierCurve: Appearance.anim.curves.emphasized } - NumberAnimation { property: "scale"; from: 0.7; to: 1; duration: Appearance.anim.durations.normal; easing.bezierCurve: Appearance.anim.curves.emphasized } - } - } - - exit: Transition { - ParallelAnimation { - NumberAnimation { property: "opacity"; from: 1; to: 0; duration: Appearance.anim.durations.small; easing.bezierCurve: Appearance.anim.curves.emphasized } - NumberAnimation { property: "scale"; from: 1; to: 0.7; duration: Appearance.anim.durations.small; easing.bezierCurve: Appearance.anim.curves.emphasized } - } - } - - function showProviderSelection(): void { - currentState = "selection"; - open(); - } - - function closeWithAnimation(): void { - close(); - } - - function showAddForm(providerType: string, defaultDisplayName: string): void { - editIndex = -1; - providerName = providerType; - displayName = defaultDisplayName; - interfaceName = ""; - - if (currentState === "selection") { - transitionToForm.start(); - } else { - currentState = "form"; - isClosing = false; - open(); - } - } - - function showEditForm(index: int): void { - const provider = Config.utilities.vpn.provider[index]; - const isObject = typeof provider === "object"; - - editIndex = index; - providerName = isObject ? (provider.name || "custom") : String(provider); - displayName = isObject ? (provider.displayName || providerName) : providerName; - interfaceName = isObject ? (provider.interface || "") : ""; - - currentState = "form"; - open(); - } - - Overlay.modal: Rectangle { - color: Qt.rgba(0, 0, 0, 0.4 * vpnDialog.opacity) - } - - onClosed: { - currentState = "selection"; - } - - SequentialAnimation { - id: transitionToForm - - ParallelAnimation { - NumberAnimation { - target: selectionContent - property: "opacity" - to: 0 - duration: Appearance.anim.durations.small - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - ScriptAction { - script: { - vpnDialog.currentState = "form"; - } - } - - ParallelAnimation { - NumberAnimation { - target: formContent - property: "opacity" - to: 1 - duration: Appearance.anim.durations.small - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - } - - background: StyledRect { - color: Colours.palette.m3surfaceContainerHigh - radius: Appearance.rounding.large - - layer.enabled: true - layer.effect: DropShadow { - color: Qt.rgba(0, 0, 0, 0.3) - radius: 16 - samples: 33 - verticalOffset: 4 - } - - Behavior on implicitHeight { - NumberAnimation { - duration: Appearance.anim.durations.normal - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - } - - contentItem: Item { - implicitHeight: vpnDialog.currentState === "selection" ? selectionContent.implicitHeight : formContent.implicitHeight - - Behavior on implicitHeight { - NumberAnimation { - duration: Appearance.anim.durations.normal - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - ColumnLayout { - id: selectionContent - - anchors.fill: parent - spacing: Appearance.spacing.normal - visible: vpnDialog.currentState === "selection" - opacity: vpnDialog.currentState === "selection" ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Appearance.anim.durations.small - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - StyledText { - text: qsTr("Add VPN Provider") - font.pointSize: Appearance.font.size.large - font.weight: 500 - } - - StyledText { - Layout.fillWidth: true - text: qsTr("Choose a provider to add") - wrapMode: Text.WordWrap - color: Colours.palette.m3outline - font.pointSize: Appearance.font.size.small - } - - Item { Layout.preferredHeight: Appearance.spacing.small } - - TextButton { - Layout.fillWidth: true - text: qsTr("NetBird") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - onClicked: { - const providers = []; - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - providers.push(Config.utilities.vpn.provider[i]); - } - providers.push({ name: "netbird", displayName: "NetBird", interface: "wt0" }); - Config.utilities.vpn.provider = providers; - Config.save(); - vpnDialog.closeWithAnimation(); - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("Tailscale") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - onClicked: { - const providers = []; - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - providers.push(Config.utilities.vpn.provider[i]); - } - providers.push({ name: "tailscale", displayName: "Tailscale", interface: "tailscale0" }); - Config.utilities.vpn.provider = providers; - Config.save(); - vpnDialog.closeWithAnimation(); - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("Cloudflare WARP") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - onClicked: { - const providers = []; - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - providers.push(Config.utilities.vpn.provider[i]); - } - providers.push({ name: "warp", displayName: "Cloudflare WARP", interface: "CloudflareWARP" }); - Config.utilities.vpn.provider = providers; - Config.save(); - vpnDialog.closeWithAnimation(); - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("WireGuard (Custom)") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - onClicked: { - vpnDialog.showAddForm("wireguard", "WireGuard"); - } - } - - Item { Layout.preferredHeight: Appearance.spacing.small } - - TextButton { - Layout.fillWidth: true - text: qsTr("Cancel") - inactiveColour: Colours.palette.m3secondaryContainer - inactiveOnColour: Colours.palette.m3onSecondaryContainer - onClicked: vpnDialog.closeWithAnimation() - } - } - - ColumnLayout { - id: formContent - - anchors.fill: parent - spacing: Appearance.spacing.normal - visible: vpnDialog.currentState === "form" - opacity: vpnDialog.currentState === "form" ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Appearance.anim.durations.small - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - StyledText { - text: vpnDialog.editIndex >= 0 ? qsTr("Edit VPN Provider") : qsTr("Add %1 VPN").arg(vpnDialog.displayName) - font.pointSize: Appearance.font.size.large - font.weight: 500 - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.smaller / 2 - - StyledText { - text: qsTr("Display Name") - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3onSurfaceVariant - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: 40 - color: displayNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: displayNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - StyledTextField { - id: displayNameField - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignLeft - text: vpnDialog.displayName - onTextChanged: vpnDialog.displayName = text - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.smaller / 2 - - StyledText { - text: qsTr("Interface (e.g., wg0, torguard)") - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3onSurfaceVariant - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: 40 - color: interfaceNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: interfaceNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - StyledTextField { - id: interfaceNameField - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignLeft - text: vpnDialog.interfaceName - onTextChanged: vpnDialog.interfaceName = text - } - } - } - - Item { Layout.preferredHeight: Appearance.spacing.normal } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.normal - - TextButton { - Layout.fillWidth: true - text: qsTr("Cancel") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - onClicked: vpnDialog.closeWithAnimation() - } - - TextButton { - Layout.fillWidth: true - text: qsTr("Save") - enabled: vpnDialog.interfaceName.length > 0 - inactiveColour: Colours.palette.m3primaryContainer - inactiveOnColour: Colours.palette.m3onPrimaryContainer - - onClicked: { - const providers = []; - const newProvider = { - name: vpnDialog.providerName, - displayName: vpnDialog.displayName || vpnDialog.interfaceName, - interface: vpnDialog.interfaceName - }; - - if (vpnDialog.editIndex >= 0) { - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - if (i === vpnDialog.editIndex) { - providers.push(newProvider); - } else { - providers.push(Config.utilities.vpn.provider[i]); - } - } - } else { - for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { - providers.push(Config.utilities.vpn.provider[i]); - } - providers.push(newProvider); - } - - Config.utilities.vpn.provider = providers; - Config.save(); - vpnDialog.closeWithAnimation(); - } - } - } - } - } - } -} diff --git a/modules/controlcenter/network/VpnSettings.qml b/modules/controlcenter/network/VpnSettings.qml deleted file mode 100644 index 7387ddc..0000000 --- a/modules/controlcenter/network/VpnSettings.qml +++ /dev/null @@ -1,232 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../components" -import qs.components -import qs.components.controls -import qs.components.containers -import qs.components.effects -import qs.services -import qs.config -import Quickshell -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -ColumnLayout { - id: root - - required property Session session - - spacing: Appearance.spacing.normal - - SettingsHeader { - icon: "vpn_key" - title: qsTr("VPN Settings") - } - - SectionHeader { - Layout.topMargin: Appearance.spacing.large - title: qsTr("General") - description: qsTr("VPN configuration") - } - - SectionContainer { - ToggleRow { - label: qsTr("VPN enabled") - checked: Config.utilities.vpn.enabled - toggle.onToggled: { - Config.utilities.vpn.enabled = checked; - Config.save(); - } - } - } - - SectionHeader { - Layout.topMargin: Appearance.spacing.large - title: qsTr("Providers") - description: qsTr("Manage VPN providers") - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - ListView { - Layout.fillWidth: true - Layout.preferredHeight: contentHeight - - interactive: false - spacing: Appearance.spacing.smaller - - model: ScriptModel { - values: Config.utilities.vpn.provider.map((provider, index) => { - const isObject = typeof provider === "object"; - const name = isObject ? (provider.name || "custom") : String(provider); - const displayName = isObject ? (provider.displayName || name) : name; - const iface = isObject ? (provider.interface || "") : ""; - - return { - index: index, - name: name, - displayName: displayName, - interface: iface, - provider: provider, - isActive: index === 0 - }; - }) - } - - delegate: Component { - StyledRect { - required property var modelData - required property int index - - width: ListView.view ? ListView.view.width : undefined - color: Colours.tPalette.m3surfaceContainerHigh - radius: Appearance.rounding.normal - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal - spacing: Appearance.spacing.normal - - MaterialIcon { - text: modelData.isActive ? "vpn_key" : "vpn_key_off" - font.pointSize: Appearance.font.size.large - color: modelData.isActive ? Colours.palette.m3primary : Colours.palette.m3outline - } - - ColumnLayout { - Layout.fillWidth: true - spacing: 0 - - StyledText { - text: modelData.displayName - font.weight: modelData.isActive ? 500 : 400 - } - - StyledText { - text: qsTr("%1 • %2").arg(modelData.name).arg(modelData.interface || qsTr("No interface")) - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3outline - } - } - - IconButton { - icon: modelData.isActive ? "arrow_downward" : "arrow_upward" - visible: !modelData.isActive || Config.utilities.vpn.provider.length > 1 - onClicked: { - if (modelData.isActive && index < Config.utilities.vpn.provider.length - 1) { - // Move down - const providers = [...Config.utilities.vpn.provider]; - const temp = providers[index]; - providers[index] = providers[index + 1]; - providers[index + 1] = temp; - Config.utilities.vpn.provider = providers; - Config.save(); - } else if (!modelData.isActive) { - // Make active (move to top) - const providers = [...Config.utilities.vpn.provider]; - const provider = providers.splice(index, 1)[0]; - providers.unshift(provider); - Config.utilities.vpn.provider = providers; - Config.save(); - } - } - } - - IconButton { - icon: "delete" - onClicked: { - const providers = [...Config.utilities.vpn.provider]; - providers.splice(index, 1); - Config.utilities.vpn.provider = providers; - Config.save(); - } - } - } - - implicitHeight: 60 - } - } - } - - TextButton { - Layout.fillWidth: true - Layout.topMargin: Appearance.spacing.normal - text: qsTr("+ Add Provider") - inactiveColour: Colours.palette.m3primaryContainer - inactiveOnColour: Colours.palette.m3onPrimaryContainer - - onClicked: { - addProviderDialog.open(); - } - } - } - - SectionHeader { - Layout.topMargin: Appearance.spacing.large - title: qsTr("Quick Add") - description: qsTr("Add common VPN providers") - } - - SectionContainer { - contentSpacing: Appearance.spacing.smaller - - TextButton { - Layout.fillWidth: true - text: qsTr("+ Add NetBird") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - - onClicked: { - const providers = [...Config.utilities.vpn.provider]; - providers.push({ - name: "netbird", - displayName: "NetBird", - interface: "wt0" - }); - Config.utilities.vpn.provider = providers; - Config.save(); - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("+ Add Tailscale") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - - onClicked: { - const providers = [...Config.utilities.vpn.provider]; - providers.push({ - name: "tailscale", - displayName: "Tailscale", - interface: "tailscale0" - }); - Config.utilities.vpn.provider = providers; - Config.save(); - } - } - - TextButton { - Layout.fillWidth: true - text: qsTr("+ Add Cloudflare WARP") - inactiveColour: Colours.tPalette.m3surfaceContainerHigh - inactiveOnColour: Colours.palette.m3onSurface - - onClicked: { - const providers = [...Config.utilities.vpn.provider]; - providers.push({ - name: "warp", - displayName: "Cloudflare WARP", - interface: "CloudflareWARP" - }); - Config.utilities.vpn.provider = providers; - Config.save(); - } - } - } -} diff --git a/modules/controlcenter/state/VpnState.qml b/modules/controlcenter/state/VpnState.qml deleted file mode 100644 index aa911f1..0000000 --- a/modules/controlcenter/state/VpnState.qml +++ /dev/null @@ -1,5 +0,0 @@ -import QtQuick - -QtObject { - property var active: null -} diff --git a/modules/controlcenter/taskbar/TaskbarPane.qml b/modules/controlcenter/taskbar/TaskbarPane.qml deleted file mode 100644 index 917b73a..0000000 --- a/modules/controlcenter/taskbar/TaskbarPane.qml +++ /dev/null @@ -1,646 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import "../components" -import qs.components -import qs.components.controls -import qs.components.effects -import qs.components.containers -import qs.services -import qs.config -import qs.utils -import Quickshell -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts - -Item { - id: root - - required property Session session - - property bool clockShowIcon: Config.bar.clock.showIcon ?? true - property bool persistent: Config.bar.persistent ?? true - property bool showOnHover: Config.bar.showOnHover ?? true - property int dragThreshold: Config.bar.dragThreshold ?? 20 - property bool showAudio: Config.bar.status.showAudio ?? true - property bool showMicrophone: Config.bar.status.showMicrophone ?? true - property bool showKbLayout: Config.bar.status.showKbLayout ?? false - property bool showNetwork: Config.bar.status.showNetwork ?? true - property bool showWifi: Config.bar.status.showWifi ?? true - property bool showBluetooth: Config.bar.status.showBluetooth ?? true - property bool showBattery: Config.bar.status.showBattery ?? true - property bool showLockStatus: Config.bar.status.showLockStatus ?? true - property bool trayBackground: Config.bar.tray.background ?? false - property bool trayCompact: Config.bar.tray.compact ?? false - property bool trayRecolour: Config.bar.tray.recolour ?? false - property int workspacesShown: Config.bar.workspaces.shown ?? 5 - property bool workspacesActiveIndicator: Config.bar.workspaces.activeIndicator ?? true - property bool workspacesOccupiedBg: Config.bar.workspaces.occupiedBg ?? false - property bool workspacesShowWindows: Config.bar.workspaces.showWindows ?? false - property bool workspacesPerMonitor: Config.bar.workspaces.perMonitorWorkspaces ?? true - property bool scrollWorkspaces: Config.bar.scrollActions.workspaces ?? true - property bool scrollVolume: Config.bar.scrollActions.volume ?? true - property bool scrollBrightness: Config.bar.scrollActions.brightness ?? true - property bool popoutActiveWindow: Config.bar.popouts.activeWindow ?? true - property bool popoutTray: Config.bar.popouts.tray ?? true - property bool popoutStatusIcons: Config.bar.popouts.statusIcons ?? true - - anchors.fill: parent - - Component.onCompleted: { - if (Config.bar.entries) { - entriesModel.clear(); - for (let i = 0; i < Config.bar.entries.length; i++) { - const entry = Config.bar.entries[i]; - entriesModel.append({ - id: entry.id, - enabled: entry.enabled !== false - }); - } - } - } - - function saveConfig(entryIndex, entryEnabled) { - Config.bar.clock.showIcon = root.clockShowIcon; - Config.bar.persistent = root.persistent; - Config.bar.showOnHover = root.showOnHover; - Config.bar.dragThreshold = root.dragThreshold; - Config.bar.status.showAudio = root.showAudio; - Config.bar.status.showMicrophone = root.showMicrophone; - Config.bar.status.showKbLayout = root.showKbLayout; - Config.bar.status.showNetwork = root.showNetwork; - Config.bar.status.showWifi = root.showWifi; - Config.bar.status.showBluetooth = root.showBluetooth; - Config.bar.status.showBattery = root.showBattery; - Config.bar.status.showLockStatus = root.showLockStatus; - Config.bar.tray.background = root.trayBackground; - Config.bar.tray.compact = root.trayCompact; - Config.bar.tray.recolour = root.trayRecolour; - Config.bar.workspaces.shown = root.workspacesShown; - Config.bar.workspaces.activeIndicator = root.workspacesActiveIndicator; - Config.bar.workspaces.occupiedBg = root.workspacesOccupiedBg; - Config.bar.workspaces.showWindows = root.workspacesShowWindows; - Config.bar.workspaces.perMonitorWorkspaces = root.workspacesPerMonitor; - Config.bar.scrollActions.workspaces = root.scrollWorkspaces; - Config.bar.scrollActions.volume = root.scrollVolume; - Config.bar.scrollActions.brightness = root.scrollBrightness; - Config.bar.popouts.activeWindow = root.popoutActiveWindow; - Config.bar.popouts.tray = root.popoutTray; - Config.bar.popouts.statusIcons = root.popoutStatusIcons; - - const entries = []; - for (let i = 0; i < entriesModel.count; i++) { - const entry = entriesModel.get(i); - let enabled = entry.enabled; - if (entryIndex !== undefined && i === entryIndex) { - enabled = entryEnabled; - } - entries.push({ - id: entry.id, - enabled: enabled - }); - } - Config.bar.entries = entries; - Config.save(); - } - - ListModel { - id: entriesModel - } - - ClippingRectangle { - id: taskbarClippingRect - anchors.fill: parent - anchors.margins: Appearance.padding.normal - anchors.leftMargin: 0 - anchors.rightMargin: Appearance.padding.normal - - radius: taskbarBorder.innerRadius - color: "transparent" - - Loader { - id: taskbarLoader - - anchors.fill: parent - anchors.margins: Appearance.padding.large + Appearance.padding.normal - anchors.leftMargin: Appearance.padding.large - anchors.rightMargin: Appearance.padding.large - - sourceComponent: taskbarContentComponent - } - } - - InnerBorder { - id: taskbarBorder - leftThickness: 0 - rightThickness: Appearance.padding.normal - } - - Component { - id: taskbarContentComponent - - StyledFlickable { - id: sidebarFlickable - flickableDirection: Flickable.VerticalFlick - contentHeight: sidebarLayout.height - - StyledScrollBar.vertical: StyledScrollBar { - flickable: sidebarFlickable - } - - ColumnLayout { - id: sidebarLayout - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - - spacing: Appearance.spacing.normal - - RowLayout { - spacing: Appearance.spacing.smaller - - StyledText { - text: qsTr("Taskbar") - font.pointSize: Appearance.font.size.large - font.weight: 500 - } - } - - SectionContainer { - Layout.fillWidth: true - alignTop: true - - StyledText { - text: qsTr("Status Icons") - font.pointSize: Appearance.font.size.normal - } - - ConnectedButtonGroup { - rootItem: root - - options: [ - { - label: qsTr("Speakers"), - propertyName: "showAudio", - onToggled: function(checked) { - root.showAudio = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Microphone"), - propertyName: "showMicrophone", - onToggled: function(checked) { - root.showMicrophone = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Keyboard"), - propertyName: "showKbLayout", - onToggled: function(checked) { - root.showKbLayout = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Network"), - propertyName: "showNetwork", - onToggled: function(checked) { - root.showNetwork = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Wifi"), - propertyName: "showWifi", - onToggled: function(checked) { - root.showWifi = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Bluetooth"), - propertyName: "showBluetooth", - onToggled: function(checked) { - root.showBluetooth = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Battery"), - propertyName: "showBattery", - onToggled: function(checked) { - root.showBattery = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Capslock"), - propertyName: "showLockStatus", - onToggled: function(checked) { - root.showLockStatus = checked; - root.saveConfig(); - } - } - ] - } - } - - RowLayout { - id: mainRowLayout - Layout.fillWidth: true - spacing: Appearance.spacing.normal - - ColumnLayout { - id: leftColumnLayout - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop - spacing: Appearance.spacing.normal - - SectionContainer { - Layout.fillWidth: true - alignTop: true - - StyledText { - text: qsTr("Workspaces") - font.pointSize: Appearance.font.size.normal - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: workspacesShownRow.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.layer(Colours.palette.m3surfaceContainer, 2) - - Behavior on implicitHeight { - Anim {} - } - - RowLayout { - id: workspacesShownRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - Layout.fillWidth: true - text: qsTr("Shown") - } - - CustomSpinBox { - min: 1 - max: 20 - value: root.workspacesShown - onValueModified: value => { - root.workspacesShown = value; - root.saveConfig(); - } - } - } - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: workspacesActiveIndicatorRow.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.layer(Colours.palette.m3surfaceContainer, 2) - - Behavior on implicitHeight { - Anim {} - } - - RowLayout { - id: workspacesActiveIndicatorRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - Layout.fillWidth: true - text: qsTr("Active indicator") - } - - StyledSwitch { - checked: root.workspacesActiveIndicator - onToggled: { - root.workspacesActiveIndicator = checked; - root.saveConfig(); - } - } - } - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: workspacesOccupiedBgRow.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.layer(Colours.palette.m3surfaceContainer, 2) - - Behavior on implicitHeight { - Anim {} - } - - RowLayout { - id: workspacesOccupiedBgRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - Layout.fillWidth: true - text: qsTr("Occupied background") - } - - StyledSwitch { - checked: root.workspacesOccupiedBg - onToggled: { - root.workspacesOccupiedBg = checked; - root.saveConfig(); - } - } - } - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: workspacesShowWindowsRow.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.layer(Colours.palette.m3surfaceContainer, 2) - - Behavior on implicitHeight { - Anim {} - } - - RowLayout { - id: workspacesShowWindowsRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - Layout.fillWidth: true - text: qsTr("Show windows") - } - - StyledSwitch { - checked: root.workspacesShowWindows - onToggled: { - root.workspacesShowWindows = checked; - root.saveConfig(); - } - } - } - } - - StyledRect { - Layout.fillWidth: true - implicitHeight: workspacesPerMonitorRow.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.layer(Colours.palette.m3surfaceContainer, 2) - - Behavior on implicitHeight { - Anim {} - } - - RowLayout { - id: workspacesPerMonitorRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - Layout.fillWidth: true - text: qsTr("Per monitor workspaces") - } - - StyledSwitch { - checked: root.workspacesPerMonitor - onToggled: { - root.workspacesPerMonitor = checked; - root.saveConfig(); - } - } - } - } - } - - SectionContainer { - Layout.fillWidth: true - alignTop: true - - StyledText { - text: qsTr("Scroll Actions") - font.pointSize: Appearance.font.size.normal - } - - ConnectedButtonGroup { - rootItem: root - - options: [ - { - label: qsTr("Workspaces"), - propertyName: "scrollWorkspaces", - onToggled: function(checked) { - root.scrollWorkspaces = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Volume"), - propertyName: "scrollVolume", - onToggled: function(checked) { - root.scrollVolume = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Brightness"), - propertyName: "scrollBrightness", - onToggled: function(checked) { - root.scrollBrightness = checked; - root.saveConfig(); - } - } - ] - } - } - } - - ColumnLayout { - id: middleColumnLayout - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop - spacing: Appearance.spacing.normal - - SectionContainer { - Layout.fillWidth: true - alignTop: true - - StyledText { - text: qsTr("Clock") - font.pointSize: Appearance.font.size.normal - } - - SwitchRow { - label: qsTr("Show clock icon") - checked: root.clockShowIcon - onToggled: checked => { - root.clockShowIcon = checked; - root.saveConfig(); - } - } - } - - SectionContainer { - Layout.fillWidth: true - alignTop: true - - StyledText { - text: qsTr("Bar Behavior") - font.pointSize: Appearance.font.size.normal - } - - SwitchRow { - label: qsTr("Persistent") - checked: root.persistent - onToggled: checked => { - root.persistent = checked; - root.saveConfig(); - } - } - - SwitchRow { - label: qsTr("Show on hover") - checked: root.showOnHover - onToggled: checked => { - root.showOnHover = checked; - root.saveConfig(); - } - } - - SectionContainer { - contentSpacing: Appearance.spacing.normal - - SliderInput { - Layout.fillWidth: true - - label: qsTr("Drag threshold") - value: root.dragThreshold - from: 0 - to: 100 - suffix: "px" - validator: IntValidator { bottom: 0; top: 100 } - formatValueFunction: (val) => Math.round(val).toString() - parseValueFunction: (text) => parseInt(text) - - onValueModified: (newValue) => { - root.dragThreshold = Math.round(newValue); - root.saveConfig(); - } - } - } - } - } - - ColumnLayout { - id: rightColumnLayout - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop - spacing: Appearance.spacing.normal - - SectionContainer { - Layout.fillWidth: true - alignTop: true - - StyledText { - text: qsTr("Popouts") - font.pointSize: Appearance.font.size.normal - } - - SwitchRow { - label: qsTr("Active window") - checked: root.popoutActiveWindow - onToggled: checked => { - root.popoutActiveWindow = checked; - root.saveConfig(); - } - } - - SwitchRow { - label: qsTr("Tray") - checked: root.popoutTray - onToggled: checked => { - root.popoutTray = checked; - root.saveConfig(); - } - } - - SwitchRow { - label: qsTr("Status icons") - checked: root.popoutStatusIcons - onToggled: checked => { - root.popoutStatusIcons = checked; - root.saveConfig(); - } - } - } - - SectionContainer { - Layout.fillWidth: true - alignTop: true - - StyledText { - text: qsTr("Tray Settings") - font.pointSize: Appearance.font.size.normal - } - - ConnectedButtonGroup { - rootItem: root - - options: [ - { - label: qsTr("Background"), - propertyName: "trayBackground", - onToggled: function(checked) { - root.trayBackground = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Compact"), - propertyName: "trayCompact", - onToggled: function(checked) { - root.trayCompact = checked; - root.saveConfig(); - } - }, - { - label: qsTr("Recolour"), - propertyName: "trayRecolour", - onToggled: function(checked) { - root.trayRecolour = checked; - root.saveConfig(); - } - } - ] - } - } - } - } - - } - } - } -} |