diff options
Diffstat (limited to 'modules')
27 files changed, 8 insertions, 6553 deletions
diff --git a/modules/areapicker/Picker.qml b/modules/areapicker/Picker.qml deleted file mode 100644 index 35b35a2..0000000 --- a/modules/areapicker/Picker.qml +++ /dev/null @@ -1,300 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.services -import qs.config -import Caelestia -import Quickshell -import Quickshell.Wayland -import QtQuick -import QtQuick.Effects - -MouseArea { - id: root - - required property LazyLoader loader - required property ShellScreen screen - - property bool onClient - - property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2 - property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0 - - property real ssx - property real ssy - - property real sx: 0 - property real sy: 0 - property real ex: screen.width - property real ey: screen.height - - property real rsx: Math.min(sx, ex) - property real rsy: Math.min(sy, ey) - property real sw: Math.abs(sx - ex) - property real sh: Math.abs(sy - ey) - - property list<var> clients: { - const mon = Hypr.monitorFor(screen); - if (!mon) - return []; - - const special = mon.lastIpcObject.specialWorkspace; - const wsId = special.name ? special.id : mon.activeWorkspace.id; - - return Hypr.toplevels.values.filter(c => c.workspace?.id === wsId).sort((a, b) => { - // Pinned first, then fullscreen, then floating, then any other - const ac = a.lastIpcObject; - const bc = b.lastIpcObject; - return (bc.pinned - ac.pinned) || ((bc.fullscreen !== 0) - (ac.fullscreen !== 0)) || (bc.floating - ac.floating); - }); - } - - function checkClientRects(x: real, y: real): void { - for (const client of clients) { - if (!client) - continue; - - let { - at: [cx, cy], - size: [cw, ch] - } = client.lastIpcObject; - cx -= screen.x; - cy -= screen.y; - if (cx <= x && cy <= y && cx + cw >= x && cy + ch >= y) { - onClient = true; - sx = cx; - sy = cy; - ex = cx + cw; - ey = cy + ch; - break; - } - } - } - - function save(): void { - const tmpfile = Qt.resolvedUrl(`/tmp/caelestia-picker-${Quickshell.processId}-${Date.now()}.png`); - CUtils.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => { - if (root.loader.clipboardOnly) { - Quickshell.execDetached(["sh", "-c", "wl-copy --type image/png < " + path]); - Quickshell.execDetached(["notify-send", "-a", "caelestia-cli", "-i", path, "Screenshot taken", "Screenshot copied to clipboard"]); - } else { - Quickshell.execDetached(["swappy", "-f", path]); - } - }); - closeAnim.start(); - } - - onClientsChanged: checkClientRects(mouseX, mouseY) - - anchors.fill: parent - opacity: 0 - hoverEnabled: true - cursorShape: Qt.CrossCursor - - Component.onCompleted: { - Hypr.extras.refreshOptions(); - - // Break binding if frozen - if (loader.freeze) - clients = clients; - - opacity = 1; - - const c = clients[0]; - if (c) { - const cx = c.lastIpcObject.at[0] - screen.x; - const cy = c.lastIpcObject.at[1] - screen.y; - onClient = true; - sx = cx; - sy = cy; - ex = cx + c.lastIpcObject.size[0]; - ey = cy + c.lastIpcObject.size[1]; - } else { - sx = screen.width / 2 - 100; - sy = screen.height / 2 - 100; - ex = screen.width / 2 + 100; - ey = screen.height / 2 + 100; - } - } - - onPressed: event => { - ssx = event.x; - ssy = event.y; - } - - onReleased: { - if (closeAnim.running) - return; - - if (root.loader.freeze) { - save(); - } else { - overlay.visible = border.visible = false; - screencopy.visible = false; - screencopy.active = true; - } - } - - onPositionChanged: event => { - const x = event.x; - const y = event.y; - - if (pressed) { - onClient = false; - sx = ssx; - sy = ssy; - ex = x; - ey = y; - } else { - checkClientRects(x, y); - } - } - - focus: true - Keys.onEscapePressed: closeAnim.start() - - SequentialAnimation { - id: closeAnim - - PropertyAction { - target: root.loader - property: "closing" - value: true - } - ParallelAnimation { - Anim { - target: root - property: "opacity" - to: 0 - duration: Appearance.anim.durations.large - } - ExAnim { - target: root - properties: "rsx,rsy" - to: 0 - } - ExAnim { - target: root - property: "sw" - to: root.screen.width - } - ExAnim { - target: root - property: "sh" - to: root.screen.height - } - } - PropertyAction { - target: root.loader - property: "activeAsync" - value: false - } - } - - Loader { - id: screencopy - - anchors.fill: parent - - active: root.loader.freeze - - sourceComponent: ScreencopyView { - captureSource: root.screen - - onHasContentChanged: { - if (hasContent && !root.loader.freeze) { - overlay.visible = border.visible = true; - root.save(); - } - } - } - } - - StyledRect { - id: overlay - - anchors.fill: parent - color: Colours.palette.m3secondaryContainer - opacity: 0.3 - - layer.enabled: true - layer.effect: MultiEffect { - maskSource: selectionWrapper - maskEnabled: true - maskInverted: true - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - } - - Item { - id: selectionWrapper - - anchors.fill: parent - layer.enabled: true - visible: false - - Rectangle { - id: selectionRect - - radius: root.realRounding - x: root.rsx - y: root.rsy - implicitWidth: root.sw - implicitHeight: root.sh - } - } - - Rectangle { - id: border - - color: "transparent" - radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0 - border.width: root.realBorderWidth - border.color: Colours.palette.m3primary - - x: selectionRect.x - root.realBorderWidth - y: selectionRect.y - root.realBorderWidth - implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2 - implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2 - - Behavior on border.color { - CAnim {} - } - } - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.large - } - } - - Behavior on rsx { - enabled: !root.pressed - - ExAnim {} - } - - Behavior on rsy { - enabled: !root.pressed - - ExAnim {} - } - - Behavior on sw { - enabled: !root.pressed - - ExAnim {} - } - - Behavior on sh { - enabled: !root.pressed - - ExAnim {} - } - - component ExAnim: Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } -} diff --git a/modules/background/DesktopClock.qml b/modules/background/DesktopClock.qml deleted file mode 100644 index 77fe447..0000000 --- a/modules/background/DesktopClock.qml +++ /dev/null @@ -1,169 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.services -import qs.config -import QtQuick -import QtQuick.Layouts -import QtQuick.Effects - -Item { - id: root - - required property Item wallpaper - required property real absX - required property real absY - - property real scale: Config.background.desktopClock.scale - readonly property bool bgEnabled: Config.background.desktopClock.background.enabled - readonly property bool blurEnabled: bgEnabled && Config.background.desktopClock.background.blur - readonly property bool invertColors: Config.background.desktopClock.invertColors - readonly property bool useLightSet: Colours.light ? !invertColors : invertColors - readonly property color safePrimary: useLightSet ? Colours.palette.m3primaryContainer : Colours.palette.m3primary - readonly property color safeSecondary: useLightSet ? Colours.palette.m3secondaryContainer : Colours.palette.m3secondary - readonly property color safeTertiary: useLightSet ? Colours.palette.m3tertiaryContainer : Colours.palette.m3tertiary - - implicitWidth: layout.implicitWidth + (Appearance.padding.large * 4 * root.scale) - implicitHeight: layout.implicitHeight + (Appearance.padding.large * 2 * root.scale) - - Item { - id: clockContainer - - anchors.fill: parent - - layer.enabled: Config.background.desktopClock.shadow.enabled - layer.effect: MultiEffect { - shadowEnabled: true - shadowColor: Colours.palette.m3shadow - shadowOpacity: Config.background.desktopClock.shadow.opacity - shadowBlur: Config.background.desktopClock.shadow.blur - } - - Loader { - anchors.fill: parent - active: root.blurEnabled - - sourceComponent: MultiEffect { - source: ShaderEffectSource { - sourceItem: root.wallpaper - sourceRect: Qt.rect(root.absX, root.absY, root.width, root.height) - } - maskSource: backgroundPlate - maskEnabled: true - blurEnabled: true - blur: 1 - blurMax: 64 - autoPaddingEnabled: false - } - } - - StyledRect { - id: backgroundPlate - - visible: root.bgEnabled - anchors.fill: parent - radius: Appearance.rounding.large * root.scale - opacity: Config.background.desktopClock.background.opacity - color: Colours.palette.m3surface - - layer.enabled: root.blurEnabled - } - - RowLayout { - id: layout - - anchors.centerIn: parent - spacing: Appearance.spacing.larger * root.scale - - RowLayout { - spacing: Appearance.spacing.small - - StyledText { - text: Time.hourStr - font.pointSize: Appearance.font.size.extraLarge * 3 * root.scale - font.weight: Font.Bold - color: root.safePrimary - } - - StyledText { - text: ":" - font.pointSize: Appearance.font.size.extraLarge * 3 * root.scale - color: root.safeTertiary - opacity: 0.8 - Layout.topMargin: -Appearance.padding.large * 1.5 * root.scale - } - - StyledText { - text: Time.minuteStr - font.pointSize: Appearance.font.size.extraLarge * 3 * root.scale - font.weight: Font.Bold - color: root.safeSecondary - } - - Loader { - Layout.alignment: Qt.AlignTop - Layout.topMargin: Appearance.padding.large * 1.4 * root.scale - - active: Config.services.useTwelveHourClock - visible: active - - sourceComponent: StyledText { - text: Time.amPmStr - font.pointSize: Appearance.font.size.large * root.scale - color: root.safeSecondary - } - } - } - - StyledRect { - Layout.fillHeight: true - Layout.preferredWidth: 4 * root.scale - Layout.topMargin: Appearance.spacing.larger * root.scale - Layout.bottomMargin: Appearance.spacing.larger * root.scale - radius: Appearance.rounding.full - color: root.safePrimary - opacity: 0.8 - } - - ColumnLayout { - spacing: 0 - - StyledText { - text: Time.format("MMMM").toUpperCase() - font.pointSize: Appearance.font.size.large * root.scale - font.letterSpacing: 4 - font.weight: Font.Bold - color: root.safeSecondary - } - - StyledText { - text: Time.format("dd") - font.pointSize: Appearance.font.size.extraLarge * root.scale - font.letterSpacing: 2 - font.weight: Font.Medium - color: root.safePrimary - } - - StyledText { - text: Time.format("dddd") - font.pointSize: Appearance.font.size.larger * root.scale - font.letterSpacing: 2 - color: root.safeSecondary - } - } - } - } - - Behavior on scale { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - Behavior on implicitWidth { - Anim { - duration: Appearance.anim.durations.small - } - } -} diff --git a/modules/background/Visualiser.qml b/modules/background/Visualiser.qml deleted file mode 100644 index c9bb9ef..0000000 --- a/modules/background/Visualiser.qml +++ /dev/null @@ -1,151 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.services -import qs.config -import Caelestia.Services -import Quickshell -import Quickshell.Widgets -import QtQuick -import QtQuick.Effects - -Item { - id: root - - required property ShellScreen screen - required property Wallpaper wallpaper - - readonly property bool shouldBeActive: Config.background.visualiser.enabled && (!Config.background.visualiser.autoHide || (Hypr.monitorFor(screen)?.activeWorkspace?.toplevels?.values.every(t => t.lastIpcObject?.floating) ?? true)) - property real offset: shouldBeActive ? 0 : screen.height * 0.2 - - opacity: shouldBeActive ? 1 : 0 - - Loader { - anchors.fill: parent - active: root.opacity > 0 && Config.background.visualiser.blur - - sourceComponent: MultiEffect { - source: root.wallpaper - maskSource: wrapper - maskEnabled: true - blurEnabled: true - blur: 1 - blurMax: 32 - autoPaddingEnabled: false - } - } - - Item { - id: wrapper - - anchors.fill: parent - layer.enabled: true - - Loader { - anchors.fill: parent - anchors.topMargin: root.offset - anchors.bottomMargin: -root.offset - - active: root.opacity > 0 - - sourceComponent: Item { - ServiceRef { - service: Audio.cava - } - - Item { - id: content - - anchors.fill: parent - anchors.margins: Config.border.thickness - anchors.leftMargin: Visibilities.bars.get(root.screen).exclusiveZone + Appearance.spacing.small * Config.background.visualiser.spacing - - Side { - content: content - } - Side { - content: content - isRight: true - } - - Behavior on anchors.leftMargin { - Anim {} - } - } - } - } - } - - Behavior on offset { - Anim {} - } - - Behavior on opacity { - Anim {} - } - - component Side: Repeater { - id: side - - required property Item content - property bool isRight - - model: Config.services.visualiserBars - - ClippingRectangle { - id: bar - - required property int modelData - property real value: Math.max(0, Math.min(1, Audio.cava.values[side.isRight ? modelData : side.count - modelData - 1])) - - clip: true - - x: modelData * ((side.content.width * 0.4) / Config.services.visualiserBars) + (side.isRight ? side.content.width * 0.6 : 0) - implicitWidth: (side.content.width * 0.4) / Config.services.visualiserBars - Appearance.spacing.small * Config.background.visualiser.spacing - - y: side.content.height - height - implicitHeight: bar.value * side.content.height * 0.4 - - color: "transparent" - topLeftRadius: Appearance.rounding.small * Config.background.visualiser.rounding - topRightRadius: Appearance.rounding.small * Config.background.visualiser.rounding - - Rectangle { - topLeftRadius: parent.topLeftRadius - topRightRadius: parent.topRightRadius - - gradient: Gradient { - orientation: Gradient.Vertical - - GradientStop { - position: 0 - color: Qt.alpha(Colours.palette.m3primary, 0.7) - - Behavior on color { - CAnim {} - } - } - GradientStop { - position: 1 - color: Qt.alpha(Colours.palette.m3inversePrimary, 0.7) - - Behavior on color { - CAnim {} - } - } - } - - anchors.left: parent.left - anchors.right: parent.right - y: parent.height - height - implicitHeight: side.content.height * 0.4 - } - - Behavior on value { - Anim { - duration: Appearance.anim.durations.small - } - } - } - } -} diff --git a/modules/background/Wallpaper.qml b/modules/background/Wallpaper.qml deleted file mode 100644 index 9b91530..0000000 --- a/modules/background/Wallpaper.qml +++ /dev/null @@ -1,111 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.images -import qs.components.filedialog -import qs.services -import qs.config -import qs.utils -import QtQuick - -Item { - id: root - - property string source: Paths.wallpaper - property Image current: one - - anchors.fill: parent - - onSourceChanged: { - if (!source) - current = null; - else if (current === one) - two.update(); - else - one.update(); - } - - Component.onCompleted: { - if (source) - Qt.callLater(() => one.update()); - } - - Loader { - anchors.fill: parent - - active: !root.source - - sourceComponent: StyledRect { - color: Colours.palette.m3surfaceContainer - - Row { - anchors.centerIn: parent - spacing: Appearance.spacing.large - - MaterialIcon { - text: "sentiment_stressed" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.extraLarge * 5 - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Wallpaper missing?") - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.extraLarge * 2 - font.bold: true - } - } - } - } - } - - Img { - id: one - } - - Img { - id: two - } - - component Img: CachingImage { - id: img - - function update(): void { - if (path === root.source) - root.current = this; - else - path = root.source; - } - - anchors.fill: parent - - opacity: 0 - scale: 0.8 - - onStatusChanged: { - if (status === Image.Ready) - root.current = this; - } - - states: State { - name: "visible" - when: root.current === img - - PropertyChanges { - img.opacity: 1 - img.scale: 1 - } - } - - transitions: Transition { - Anim { - target: img - properties: "opacity,scale" - } - } - } -} diff --git a/modules/bar/components/workspaces/SpecialWorkspaces.qml b/modules/bar/components/workspaces/SpecialWorkspaces.qml deleted file mode 100644 index ad85af8..0000000 --- a/modules/bar/components/workspaces/SpecialWorkspaces.qml +++ /dev/null @@ -1,359 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.effects -import qs.services -import qs.utils -import qs.config -import Quickshell -import Quickshell.Hyprland -import QtQuick -import QtQuick.Layouts - -Item { - id: root - - required property ShellScreen screen - readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen) - readonly property string activeSpecial: (Config.bar.workspaces.perMonitorWorkspaces ? monitor : Hypr.focusedMonitor)?.lastIpcObject?.specialWorkspace?.name ?? "" - - layer.enabled: true - layer.effect: OpacityMask { - maskSource: mask - } - - Item { - id: mask - - anchors.fill: parent - layer.enabled: true - visible: false - - Rectangle { - anchors.fill: parent - radius: Appearance.rounding.full - - gradient: Gradient { - orientation: Gradient.Vertical - - GradientStop { - position: 0 - color: Qt.rgba(0, 0, 0, 0) - } - GradientStop { - position: 0.3 - color: Qt.rgba(0, 0, 0, 1) - } - GradientStop { - position: 0.7 - color: Qt.rgba(0, 0, 0, 1) - } - GradientStop { - position: 1 - color: Qt.rgba(0, 0, 0, 0) - } - } - } - - Rectangle { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - radius: Appearance.rounding.full - implicitHeight: parent.height / 2 - opacity: view.contentY > 0 ? 0 : 1 - - Behavior on opacity { - Anim {} - } - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - - radius: Appearance.rounding.full - implicitHeight: parent.height / 2 - opacity: view.contentY < view.contentHeight - parent.height + Appearance.padding.small ? 0 : 1 - - Behavior on opacity { - Anim {} - } - } - } - - ListView { - id: view - - anchors.fill: parent - spacing: Appearance.spacing.normal - interactive: false - - currentIndex: model.values.findIndex(w => w.name === root.activeSpecial) - onCurrentIndexChanged: currentIndex = Qt.binding(() => model.values.findIndex(w => w.name === root.activeSpecial)) - - model: ScriptModel { - values: Hypr.workspaces.values.filter(w => w.name.startsWith("special:") && (!Config.bar.workspaces.perMonitorWorkspaces || w.monitor === root.monitor)) - } - - preferredHighlightBegin: 0 - preferredHighlightEnd: height - highlightRangeMode: ListView.StrictlyEnforceRange - - highlightFollowsCurrentItem: false - highlight: Item { - y: view.currentItem?.y ?? 0 - implicitHeight: view.currentItem?.size ?? 0 - - Behavior on y { - Anim {} - } - } - - delegate: ColumnLayout { - id: ws - - required property HyprlandWorkspace modelData - readonly property int size: label.Layout.preferredHeight + (hasWindows ? windows.implicitHeight + Appearance.padding.small : 0) - property int wsId - property string icon - property bool hasWindows - - anchors.left: view.contentItem.left - anchors.right: view.contentItem.right - - spacing: 0 - - Component.onCompleted: { - wsId = modelData.id; - icon = Icons.getSpecialWsIcon(modelData.name); - hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && modelData.lastIpcObject.windows > 0; - } - - // Hacky thing cause modelData gets destroyed before the remove anim finishes - Connections { - target: ws.modelData - - function onIdChanged(): void { - if (ws.modelData) - ws.wsId = ws.modelData.id; - } - - function onNameChanged(): void { - if (ws.modelData) - ws.icon = Icons.getSpecialWsIcon(ws.modelData.name); - } - - function onLastIpcObjectChanged(): void { - if (ws.modelData) - ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0; - } - } - - Connections { - target: Config.bar.workspaces - - function onShowWindowsOnSpecialWorkspacesChanged(): void { - if (ws.modelData) - ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0; - } - } - - Loader { - id: label - - Layout.alignment: Qt.AlignHCenter | Qt.AlignTop - Layout.preferredHeight: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 - - sourceComponent: ws.icon.length === 1 ? letterComp : iconComp - - Component { - id: iconComp - - MaterialIcon { - fill: 1 - text: ws.icon - verticalAlignment: Qt.AlignVCenter - } - } - - Component { - id: letterComp - - StyledText { - text: ws.icon - verticalAlignment: Qt.AlignVCenter - } - } - } - - Loader { - id: windows - - Layout.alignment: Qt.AlignHCenter - Layout.fillHeight: true - Layout.preferredHeight: implicitHeight - - visible: active - active: ws.hasWindows - - sourceComponent: Column { - spacing: 0 - - add: Transition { - Anim { - properties: "scale" - from: 0 - to: 1 - easing.bezierCurve: Appearance.anim.curves.standardDecel - } - } - - move: Transition { - Anim { - properties: "scale" - to: 1 - easing.bezierCurve: Appearance.anim.curves.standardDecel - } - Anim { - properties: "x,y" - } - } - - Repeater { - model: ScriptModel { - values: Hypr.toplevels.values.filter(c => c.workspace?.id === ws.wsId) - } - - MaterialIcon { - required property var modelData - - grade: 0 - text: Icons.getAppCategoryIcon(modelData.lastIpcObject.class, "terminal") - color: Colours.palette.m3onSurfaceVariant - } - } - } - - Behavior on Layout.preferredHeight { - Anim {} - } - } - } - - add: Transition { - Anim { - properties: "scale" - from: 0 - to: 1 - easing.bezierCurve: Appearance.anim.curves.standardDecel - } - } - - remove: Transition { - Anim { - property: "scale" - to: 0.5 - duration: Appearance.anim.durations.small - } - Anim { - property: "opacity" - to: 0 - duration: Appearance.anim.durations.small - } - } - - move: Transition { - Anim { - properties: "scale" - to: 1 - easing.bezierCurve: Appearance.anim.curves.standardDecel - } - Anim { - properties: "x,y" - } - } - - displaced: Transition { - Anim { - properties: "scale" - to: 1 - easing.bezierCurve: Appearance.anim.curves.standardDecel - } - Anim { - properties: "x,y" - } - } - } - - Loader { - active: Config.bar.workspaces.activeIndicator - anchors.fill: parent - - sourceComponent: Item { - StyledClippingRect { - id: indicator - - anchors.left: parent.left - anchors.right: parent.right - - y: (view.currentItem?.y ?? 0) - view.contentY - implicitHeight: view.currentItem?.size ?? 0 - - color: Colours.palette.m3tertiary - radius: Appearance.rounding.full - - Colouriser { - source: view - sourceColor: Colours.palette.m3onSurface - colorizationColor: Colours.palette.m3onTertiary - - anchors.horizontalCenter: parent.horizontalCenter - - x: 0 - y: -indicator.y - implicitWidth: view.width - implicitHeight: view.height - } - - Behavior on y { - Anim { - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - Behavior on implicitHeight { - Anim { - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - } - } - } - - MouseArea { - property real startY - - anchors.fill: view - - drag.target: view.contentItem - drag.axis: Drag.YAxis - drag.maximumY: 0 - drag.minimumY: Math.min(0, view.height - view.contentHeight - Appearance.padding.small) - - onPressed: event => startY = event.y - - onClicked: event => { - if (Math.abs(event.y - startY) > drag.threshold) - return; - - const ws = view.itemAt(event.x, event.y); - if (ws?.modelData) - Hypr.dispatch(`togglespecialworkspace ${ws.modelData.name.slice(8)}`); - else - Hypr.dispatch("togglespecialworkspace special"); - } - } -} 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(); - } - } - ] - } - } - } - } - - } - } - } -} diff --git a/modules/launcher/items/SchemeItem.qml b/modules/launcher/items/SchemeItem.qml deleted file mode 100644 index 3ff1846..0000000 --- a/modules/launcher/items/SchemeItem.qml +++ /dev/null @@ -1,104 +0,0 @@ -import "../services" -import qs.components -import qs.services -import qs.config -import QtQuick - -Item { - id: root - - required property Schemes.Scheme modelData - required property var list - - implicitHeight: Config.launcher.sizes.itemHeight - - anchors.left: parent?.left - anchors.right: parent?.right - - StateLayer { - radius: Appearance.rounding.normal - - function onClicked(): void { - root.modelData?.onClicked(root.list); - } - } - - Item { - anchors.fill: parent - anchors.leftMargin: Appearance.padding.larger - anchors.rightMargin: Appearance.padding.larger - anchors.margins: Appearance.padding.smaller - - StyledRect { - id: preview - - anchors.verticalCenter: parent.verticalCenter - - border.width: 1 - border.color: Qt.alpha(`#${root.modelData?.colours?.outline}`, 0.5) - - color: `#${root.modelData?.colours?.surface}` - radius: Appearance.rounding.full - implicitWidth: parent.height * 0.8 - implicitHeight: parent.height * 0.8 - - 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: `#${root.modelData?.colours?.primary}` - radius: Appearance.rounding.full - } - } - } - - Column { - anchors.left: preview.right - anchors.leftMargin: Appearance.spacing.normal - anchors.verticalCenter: parent.verticalCenter - - width: parent.width - preview.width - anchors.leftMargin - (current.active ? current.width + Appearance.spacing.normal : 0) - spacing: 0 - - StyledText { - text: root.modelData?.flavour ?? "" - font.pointSize: Appearance.font.size.normal - } - - StyledText { - text: root.modelData?.name ?? "" - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3outline - - elide: Text.ElideRight - anchors.left: parent.left - anchors.right: parent.right - } - } - - Loader { - id: current - - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - active: `${root.modelData?.name} ${root.modelData?.flavour}` === Schemes.currentScheme - - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large - } - } - } -} diff --git a/modules/launcher/items/VariantItem.qml b/modules/launcher/items/VariantItem.qml deleted file mode 100644 index 5c34fa8..0000000 --- a/modules/launcher/items/VariantItem.qml +++ /dev/null @@ -1,80 +0,0 @@ -import "../services" -import qs.components -import qs.services -import qs.config -import QtQuick - -Item { - id: root - - required property M3Variants.Variant modelData - required property var list - - implicitHeight: Config.launcher.sizes.itemHeight - - anchors.left: parent?.left - anchors.right: parent?.right - - StateLayer { - radius: Appearance.rounding.normal - - function onClicked(): void { - root.modelData?.onClicked(root.list); - } - } - - Item { - anchors.fill: parent - anchors.leftMargin: Appearance.padding.larger - anchors.rightMargin: Appearance.padding.larger - anchors.margins: Appearance.padding.smaller - - MaterialIcon { - id: icon - - text: root.modelData?.icon ?? "" - font.pointSize: Appearance.font.size.extraLarge - - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.left: icon.right - anchors.leftMargin: Appearance.spacing.larger - anchors.verticalCenter: icon.verticalCenter - - width: parent.width - icon.width - anchors.leftMargin - (current.active ? current.width + Appearance.spacing.normal : 0) - spacing: 0 - - StyledText { - text: root.modelData?.name ?? "" - font.pointSize: Appearance.font.size.normal - } - - StyledText { - text: root.modelData?.description ?? "" - font.pointSize: Appearance.font.size.small - color: Colours.palette.m3outline - - elide: Text.ElideRight - anchors.left: parent.left - anchors.right: parent.right - } - } - - Loader { - id: current - - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - active: root.modelData?.variant === Schemes.currentVariant - - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large - } - } - } -} diff --git a/modules/launcher/services/Apps.qml b/modules/launcher/services/Apps.qml index 79f3754..0c392c6 100644 --- a/modules/launcher/services/Apps.qml +++ b/modules/launcher/services/Apps.qml @@ -48,8 +48,8 @@ Searcher { keys = ["keywords", "name"]; weights = [0.9, 0.1]; } else { - keys = ["name"]; - weights = [1]; + keys = ["name", "execString"]; + weights = [1, 0.1]; if (!search.startsWith(`${prefix}t `)) return query(search).map(e => e.entry); @@ -66,7 +66,7 @@ Searcher { } list: appDb.apps - useFuzzy: Config.launcher.useFuzzy.apps + useFuzzy: Config.launcher.useFuzzy AppDb { id: appDb diff --git a/modules/lock/Center.qml b/modules/lock/Center.qml deleted file mode 100644 index a120f5b..0000000 --- a/modules/lock/Center.qml +++ /dev/null @@ -1,415 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.controls -import qs.services -import qs.config -import qs.utils -import QtQuick -import QtQuick.Layouts - -ColumnLayout { - id: root - - required property var lock - readonly property real centerScale: Math.min(1, (lock.screen?.height ?? 1440) / 1440) - readonly property int centerWidth: Config.lock.sizes.centerWidth * centerScale - - Layout.preferredWidth: centerWidth - Layout.fillWidth: false - Layout.fillHeight: true - - spacing: Appearance.spacing.large * 2 - - RowLayout { - Layout.alignment: Qt.AlignHCenter - spacing: Appearance.spacing.small - - StyledText { - Layout.alignment: Qt.AlignVCenter - text: Time.hourStr - color: Colours.palette.m3secondary - font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) - font.family: Appearance.font.family.clock - font.bold: true - } - - StyledText { - Layout.alignment: Qt.AlignVCenter - text: ":" - color: Colours.palette.m3primary - font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) - font.family: Appearance.font.family.clock - font.bold: true - } - - StyledText { - Layout.alignment: Qt.AlignVCenter - text: Time.minuteStr - color: Colours.palette.m3secondary - font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) - font.family: Appearance.font.family.clock - font.bold: true - } - - Loader { - Layout.leftMargin: Appearance.spacing.small - Layout.alignment: Qt.AlignVCenter - - active: Config.services.useTwelveHourClock - visible: active - - sourceComponent: StyledText { - text: Time.amPmStr - color: Colours.palette.m3primary - font.pointSize: Math.floor(Appearance.font.size.extraLarge * 2 * root.centerScale) - font.family: Appearance.font.family.clock - font.bold: true - } - } - } - - StyledText { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: -Appearance.padding.large * 2 - - text: Time.format("dddd, d MMMM yyyy") - color: Colours.palette.m3tertiary - font.pointSize: Math.floor(Appearance.font.size.extraLarge * root.centerScale) - font.family: Appearance.font.family.mono - font.bold: true - } - - StyledClippingRect { - Layout.topMargin: Appearance.spacing.large * 2 - Layout.alignment: Qt.AlignHCenter - - implicitWidth: root.centerWidth / 2 - implicitHeight: root.centerWidth / 2 - - color: Colours.tPalette.m3surfaceContainer - radius: Appearance.rounding.full - - MaterialIcon { - anchors.centerIn: parent - - text: "person" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Math.floor(root.centerWidth / 4) - } - - Image { - id: pfp - - anchors.fill: parent - source: Paths.face - } - } - - StyledRect { - Layout.alignment: Qt.AlignHCenter - - implicitWidth: root.centerWidth * 0.8 - implicitHeight: input.implicitHeight + Appearance.padding.small * 2 - - color: Colours.tPalette.m3surfaceContainer - radius: Appearance.rounding.full - - focus: true - onActiveFocusChanged: { - if (!activeFocus) - forceActiveFocus(); - } - - Keys.onPressed: event => { - if (root.lock.unlocking) - return; - - if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) - inputField.placeholder.animate = false; - - root.lock.pam.handleKey(event); - } - - StateLayer { - hoverEnabled: false - cursorShape: Qt.IBeamCursor - - function onClicked(): void { - parent.forceActiveFocus(); - } - } - - RowLayout { - id: input - - anchors.fill: parent - anchors.margins: Appearance.padding.small - spacing: Appearance.spacing.normal - - Item { - implicitWidth: implicitHeight - implicitHeight: fprintIcon.implicitHeight + Appearance.padding.small * 2 - - MaterialIcon { - id: fprintIcon - - anchors.centerIn: parent - animate: true - text: { - if (root.lock.pam.fprint.tries >= Config.lock.maxFprintTries) - return "fingerprint_off"; - if (root.lock.pam.fprint.active) - return "fingerprint"; - return "lock"; - } - color: root.lock.pam.fprint.tries >= Config.lock.maxFprintTries ? Colours.palette.m3error : Colours.palette.m3onSurface - opacity: root.lock.pam.passwd.active ? 0 : 1 - - Behavior on opacity { - Anim {} - } - } - - CircularIndicator { - anchors.fill: parent - running: root.lock.pam.passwd.active - } - } - - InputField { - id: inputField - - pam: root.lock.pam - } - - StyledRect { - implicitWidth: implicitHeight - implicitHeight: enterIcon.implicitHeight + Appearance.padding.small * 2 - - color: root.lock.pam.buffer ? Colours.palette.m3primary : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) - radius: Appearance.rounding.full - - StateLayer { - color: root.lock.pam.buffer ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface - - function onClicked(): void { - root.lock.pam.passwd.start(); - } - } - - MaterialIcon { - id: enterIcon - - anchors.centerIn: parent - text: "arrow_forward" - color: root.lock.pam.buffer ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface - font.weight: 500 - } - } - } - } - - Item { - Layout.fillWidth: true - Layout.topMargin: -Appearance.spacing.large - - implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight) - - Behavior on implicitHeight { - Anim {} - } - - StyledText { - id: stateMessage - - readonly property string msg: { - if (Hypr.kbLayout !== Hypr.defaultKbLayout) { - if (Hypr.capsLock && Hypr.numLock) - return qsTr("Caps lock and Num lock are ON.\nKeyboard layout: %1").arg(Hypr.kbLayoutFull); - if (Hypr.capsLock) - return qsTr("Caps lock is ON. Kb layout: %1").arg(Hypr.kbLayoutFull); - if (Hypr.numLock) - return qsTr("Num lock is ON. Kb layout: %1").arg(Hypr.kbLayoutFull); - return qsTr("Keyboard layout: %1").arg(Hypr.kbLayoutFull); - } - - if (Hypr.capsLock && Hypr.numLock) - return qsTr("Caps lock and Num lock are ON."); - if (Hypr.capsLock) - return qsTr("Caps lock is ON."); - if (Hypr.numLock) - return qsTr("Num lock is ON."); - - return ""; - } - - property bool shouldBeVisible - - onMsgChanged: { - if (msg) { - if (opacity > 0) { - animate = true; - text = msg; - animate = false; - } else { - text = msg; - } - shouldBeVisible = true; - } else { - shouldBeVisible = false; - } - } - - anchors.left: parent.left - anchors.right: parent.right - - scale: shouldBeVisible && !message.msg ? 1 : 0.7 - opacity: shouldBeVisible && !message.msg ? 1 : 0 - color: Colours.palette.m3onSurfaceVariant - animateProp: "opacity" - - font.family: Appearance.font.family.mono - horizontalAlignment: Qt.AlignHCenter - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - lineHeight: 1.2 - - Behavior on scale { - Anim {} - } - - Behavior on opacity { - Anim {} - } - } - - StyledText { - id: message - - readonly property Pam pam: root.lock.pam - readonly property string msg: { - if (pam.fprintState === "error") - return qsTr("FP ERROR: %1").arg(pam.fprint.message); - if (pam.state === "error") - return qsTr("PW ERROR: %1").arg(pam.passwd.message); - - if (pam.lockMessage) - return pam.lockMessage; - - if (pam.state === "max" && pam.fprintState === "max") - return qsTr("Maximum password and fingerprint attempts reached."); - if (pam.state === "max") { - if (pam.fprint.available) - return qsTr("Maximum password attempts reached. Please use fingerprint."); - return qsTr("Maximum password attempts reached."); - } - if (pam.fprintState === "max") - return qsTr("Maximum fingerprint attempts reached. Please use password."); - - if (pam.state === "fail") { - if (pam.fprint.available) - return qsTr("Incorrect password. Please try again or use fingerprint."); - return qsTr("Incorrect password. Please try again."); - } - if (pam.fprintState === "fail") - return qsTr("Fingerprint not recognized (%1/%2). Please try again or use password.").arg(pam.fprint.tries).arg(Config.lock.maxFprintTries); - - return ""; - } - - anchors.left: parent.left - anchors.right: parent.right - - scale: 0.7 - opacity: 0 - color: Colours.palette.m3error - - font.pointSize: Appearance.font.size.small - font.family: Appearance.font.family.mono - horizontalAlignment: Qt.AlignHCenter - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - - onMsgChanged: { - if (msg) { - if (opacity > 0) { - animate = true; - text = msg; - animate = false; - - exitAnim.stop(); - if (scale < 1) - appearAnim.restart(); - else - flashAnim.restart(); - } else { - text = msg; - exitAnim.stop(); - appearAnim.restart(); - } - } else { - appearAnim.stop(); - flashAnim.stop(); - exitAnim.start(); - } - } - - Connections { - target: root.lock.pam - - function onFlashMsg(): void { - exitAnim.stop(); - if (message.scale < 1) - appearAnim.restart(); - else - flashAnim.restart(); - } - } - - Anim { - id: appearAnim - - target: message - properties: "scale,opacity" - to: 1 - onFinished: flashAnim.restart() - } - - SequentialAnimation { - id: flashAnim - - loops: 2 - - FlashAnim { - to: 0.3 - } - FlashAnim { - to: 1 - } - } - - ParallelAnimation { - id: exitAnim - - Anim { - target: message - property: "scale" - to: 0.7 - duration: Appearance.anim.durations.large - } - Anim { - target: message - property: "opacity" - to: 0 - duration: Appearance.anim.durations.large - } - } - } - } - - component FlashAnim: NumberAnimation { - target: message - property: "opacity" - duration: Appearance.anim.durations.small - easing.type: Easing.Linear - } -} diff --git a/modules/lock/Fetch.qml b/modules/lock/Fetch.qml deleted file mode 100644 index ded5608..0000000 --- a/modules/lock/Fetch.qml +++ /dev/null @@ -1,165 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.effects -import qs.services -import qs.config -import qs.utils -import Quickshell.Services.UPower -import QtQuick -import QtQuick.Layouts - -ColumnLayout { - id: root - - anchors.fill: parent - anchors.margins: Appearance.padding.large * 2 - anchors.topMargin: Appearance.padding.large - - spacing: Appearance.spacing.small - - RowLayout { - Layout.fillWidth: true - Layout.fillHeight: false - spacing: Appearance.spacing.normal - - StyledRect { - implicitWidth: prompt.implicitWidth + Appearance.padding.normal * 2 - implicitHeight: prompt.implicitHeight + Appearance.padding.normal * 2 - - color: Colours.palette.m3primary - radius: Appearance.rounding.small - - MonoText { - id: prompt - - anchors.centerIn: parent - text: ">" - font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal - color: Colours.palette.m3onPrimary - } - } - - MonoText { - Layout.fillWidth: true - text: "caelestiafetch.sh" - font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal - elide: Text.ElideRight - } - - WrappedLoader { - Layout.fillHeight: true - active: !iconLoader.active - - sourceComponent: OsLogo {} - } - } - - RowLayout { - Layout.fillWidth: true - Layout.fillHeight: false - spacing: height * 0.15 - - WrappedLoader { - id: iconLoader - - Layout.fillHeight: true - active: root.width > 320 - - sourceComponent: OsLogo {} - } - - ColumnLayout { - Layout.fillWidth: true - Layout.topMargin: Appearance.padding.normal - Layout.bottomMargin: Appearance.padding.normal - Layout.leftMargin: iconLoader.active ? 0 : width * 0.1 - spacing: Appearance.spacing.normal - - WrappedLoader { - Layout.fillWidth: true - active: !batLoader.active && root.height > 200 - - sourceComponent: FetchText { - text: `OS : ${SysInfo.osPrettyName || SysInfo.osName}` - } - } - - WrappedLoader { - Layout.fillWidth: true - active: root.height > (batLoader.active ? 200 : 110) - - sourceComponent: FetchText { - text: `WM : ${SysInfo.wm}` - } - } - - WrappedLoader { - Layout.fillWidth: true - active: !batLoader.active || root.height > 110 - - sourceComponent: FetchText { - text: `USER: ${SysInfo.user}` - } - } - - FetchText { - text: `UP : ${SysInfo.uptime}` - } - - WrappedLoader { - id: batLoader - - Layout.fillWidth: true - active: UPower.displayDevice.isLaptopBattery - - sourceComponent: FetchText { - text: `BATT: ${[UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state) ? "(+) " : ""}${Math.round(UPower.displayDevice.percentage * 100)}%` - } - } - } - } - - WrappedLoader { - Layout.alignment: Qt.AlignHCenter - active: root.height > 180 - - sourceComponent: RowLayout { - spacing: Appearance.spacing.large - - Repeater { - model: Math.max(0, Math.min(8, root.width / (Appearance.font.size.larger * 2 + Appearance.spacing.large))) - - StyledRect { - required property int index - - implicitWidth: implicitHeight - implicitHeight: Appearance.font.size.larger * 2 - color: Colours.palette[`term${index}`] - radius: Appearance.rounding.small - } - } - } - } - - component WrappedLoader: Loader { - visible: active - } - - component OsLogo: ColouredIcon { - source: SysInfo.osLogo - implicitSize: height - colour: Colours.palette.m3primary - layer.enabled: Config.lock.recolourLogo || SysInfo.isDefaultLogo - } - - component FetchText: MonoText { - Layout.fillWidth: true - font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal - elide: Text.ElideRight - } - - component MonoText: StyledText { - font.family: Appearance.font.family.mono - } -} diff --git a/modules/lock/NotifDock.qml b/modules/lock/NotifDock.qml deleted file mode 100644 index 01f7e4b..0000000 --- a/modules/lock/NotifDock.qml +++ /dev/null @@ -1,145 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.containers -import qs.components.effects -import qs.services -import qs.config -import Quickshell -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts - -ColumnLayout { - id: root - - required property var lock - - anchors.fill: parent - anchors.margins: Appearance.padding.large - - spacing: Appearance.spacing.smaller - - StyledText { - Layout.fillWidth: true - text: Notifs.list.length > 0 ? qsTr("%1 notification%2").arg(Notifs.list.length).arg(Notifs.list.length === 1 ? "" : "s") : qsTr("Notifications") - color: Colours.palette.m3outline - font.family: Appearance.font.family.mono - font.weight: 500 - elide: Text.ElideRight - } - - ClippingRectangle { - id: clipRect - - Layout.fillWidth: true - Layout.fillHeight: true - - radius: Appearance.rounding.small - color: "transparent" - - Loader { - anchors.centerIn: parent - active: opacity > 0 - opacity: Notifs.list.length > 0 ? 0 : 1 - - sourceComponent: ColumnLayout { - spacing: Appearance.spacing.large - - Image { - asynchronous: true - source: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/dino.png`) - fillMode: Image.PreserveAspectFit - sourceSize.width: clipRect.width * 0.8 - - layer.enabled: true - layer.effect: Colouriser { - colorizationColor: Colours.palette.m3outlineVariant - brightness: 1 - } - } - - StyledText { - Layout.alignment: Qt.AlignHCenter - text: qsTr("No Notifications") - color: Colours.palette.m3outlineVariant - font.pointSize: Appearance.font.size.large - font.family: Appearance.font.family.mono - font.weight: 500 - } - } - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.extraLarge - } - } - } - - StyledListView { - anchors.fill: parent - - spacing: Appearance.spacing.small - clip: true - - model: ScriptModel { - values: { - const list = Notifs.notClosed.map(n => [n.appName, null]); - return [...new Map(list).keys()]; - } - } - - delegate: NotifGroup {} - - add: Transition { - Anim { - property: "opacity" - from: 0 - to: 1 - } - Anim { - property: "scale" - from: 0 - to: 1 - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - remove: Transition { - Anim { - property: "opacity" - to: 0 - } - Anim { - property: "scale" - to: 0.6 - } - } - - move: Transition { - Anim { - properties: "opacity,scale" - to: 1 - } - Anim { - property: "y" - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - displaced: Transition { - Anim { - properties: "opacity,scale" - to: 1 - } - Anim { - property: "y" - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - } - } -} diff --git a/modules/lock/NotifGroup.qml b/modules/lock/NotifGroup.qml deleted file mode 100644 index 7796090..0000000 --- a/modules/lock/NotifGroup.qml +++ /dev/null @@ -1,316 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.effects -import qs.services -import qs.config -import qs.utils -import Quickshell -import Quickshell.Widgets -import Quickshell.Services.Notifications -import QtQuick -import QtQuick.Layouts - -StyledRect { - id: root - - required property string modelData - - readonly property list<var> notifs: Notifs.list.filter(notif => notif.appName === modelData) - readonly property string image: notifs.find(n => n.image.length > 0)?.image ?? "" - readonly property string appIcon: notifs.find(n => n.appIcon.length > 0)?.appIcon ?? "" - readonly property string urgency: notifs.some(n => n.urgency === NotificationUrgency.Critical) ? "critical" : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? "normal" : "low" - - property bool expanded - - anchors.left: parent?.left - anchors.right: parent?.right - implicitHeight: content.implicitHeight + Appearance.padding.normal * 2 - - clip: true - radius: Appearance.rounding.normal - color: root.urgency === "critical" ? Colours.palette.m3secondaryContainer : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) - - RowLayout { - id: content - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Appearance.padding.normal - - spacing: Appearance.spacing.normal - - Item { - Layout.alignment: Qt.AlignLeft | Qt.AlignTop - implicitWidth: Config.notifs.sizes.image - implicitHeight: Config.notifs.sizes.image - - Component { - id: imageComp - - Image { - source: Qt.resolvedUrl(root.image) - fillMode: Image.PreserveAspectCrop - cache: false - asynchronous: true - width: Config.notifs.sizes.image - height: Config.notifs.sizes.image - } - } - - Component { - id: appIconComp - - ColouredIcon { - implicitSize: Math.round(Config.notifs.sizes.image * 0.6) - source: Quickshell.iconPath(root.appIcon) - colour: root.urgency === "critical" ? Colours.palette.m3onError : root.urgency === "low" ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer - layer.enabled: root.appIcon.endsWith("symbolic") - } - } - - Component { - id: materialIconComp - - MaterialIcon { - text: Icons.getNotifIcon(root.notifs[0]?.summary, root.urgency) - color: root.urgency === "critical" ? Colours.palette.m3onError : root.urgency === "low" ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer - font.pointSize: Appearance.font.size.large - } - } - - ClippingRectangle { - anchors.fill: parent - color: root.urgency === "critical" ? Colours.palette.m3error : root.urgency === "low" ? Colours.layer(Colours.palette.m3surfaceContainerHighest, 3) : Colours.palette.m3secondaryContainer - radius: Appearance.rounding.full - - Loader { - anchors.centerIn: parent - sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp - } - } - - Loader { - anchors.right: parent.right - anchors.bottom: parent.bottom - active: root.appIcon && root.image - - sourceComponent: StyledRect { - implicitWidth: Config.notifs.sizes.badge - implicitHeight: Config.notifs.sizes.badge - - color: root.urgency === "critical" ? Colours.palette.m3error : root.urgency === "low" ? Colours.palette.m3surfaceContainerHighest : Colours.palette.m3secondaryContainer - radius: Appearance.rounding.full - - ColouredIcon { - anchors.centerIn: parent - implicitSize: Math.round(Config.notifs.sizes.badge * 0.6) - source: Quickshell.iconPath(root.appIcon) - colour: root.urgency === "critical" ? Colours.palette.m3onError : root.urgency === "low" ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer - layer.enabled: root.appIcon.endsWith("symbolic") - } - } - } - } - - ColumnLayout { - Layout.topMargin: -Appearance.padding.small - Layout.bottomMargin: -Appearance.padding.small / 2 - (root.expanded ? 0 : spacing) - Layout.fillWidth: true - spacing: Math.round(Appearance.spacing.small / 2) - - RowLayout { - Layout.bottomMargin: -parent.spacing - Layout.fillWidth: true - spacing: Appearance.spacing.smaller - - StyledText { - Layout.fillWidth: true - text: root.modelData - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.small - elide: Text.ElideRight - } - - StyledText { - animate: true - text: root.notifs[0]?.timeStr ?? "" - color: Colours.palette.m3outline - font.pointSize: Appearance.font.size.small - } - - StyledRect { - implicitWidth: expandBtn.implicitWidth + Appearance.padding.smaller * 2 - implicitHeight: groupCount.implicitHeight + Appearance.padding.small - - color: root.urgency === "critical" ? Colours.palette.m3error : Colours.layer(Colours.palette.m3surfaceContainerHighest, 2) - radius: Appearance.rounding.full - - opacity: root.notifs.length > Config.notifs.groupPreviewNum ? 1 : 0 - Layout.preferredWidth: root.notifs.length > Config.notifs.groupPreviewNum ? implicitWidth : 0 - - StateLayer { - color: root.urgency === "critical" ? Colours.palette.m3onError : Colours.palette.m3onSurface - - function onClicked(): void { - root.expanded = !root.expanded; - } - } - - RowLayout { - id: expandBtn - - anchors.centerIn: parent - spacing: Appearance.spacing.small / 2 - - StyledText { - id: groupCount - - Layout.leftMargin: Appearance.padding.small / 2 - animate: true - text: root.notifs.length - color: root.urgency === "critical" ? Colours.palette.m3onError : Colours.palette.m3onSurface - font.pointSize: Appearance.font.size.small - } - - MaterialIcon { - Layout.rightMargin: -Appearance.padding.small / 2 - animate: true - text: root.expanded ? "expand_less" : "expand_more" - color: root.urgency === "critical" ? Colours.palette.m3onError : Colours.palette.m3onSurface - } - } - - Behavior on opacity { - Anim {} - } - - Behavior on Layout.preferredWidth { - Anim {} - } - } - } - - Repeater { - model: ScriptModel { - values: root.notifs.slice(0, Config.notifs.groupPreviewNum) - } - - NotifLine { - id: notif - - ParallelAnimation { - running: true - - Anim { - target: notif - property: "opacity" - from: 0 - to: 1 - } - Anim { - target: notif - property: "scale" - from: 0.7 - to: 1 - } - Anim { - target: notif.Layout - property: "preferredHeight" - from: 0 - to: notif.implicitHeight - } - } - - ParallelAnimation { - running: notif.modelData.closed - onFinished: notif.modelData.unlock(notif) - - Anim { - target: notif - property: "opacity" - to: 0 - } - Anim { - target: notif - property: "scale" - to: 0.7 - } - Anim { - target: notif.Layout - property: "preferredHeight" - to: 0 - } - } - } - } - - Loader { - Layout.fillWidth: true - - opacity: root.expanded ? 1 : 0 - Layout.preferredHeight: root.expanded ? implicitHeight : 0 - active: opacity > 0 - - sourceComponent: ColumnLayout { - Repeater { - model: ScriptModel { - values: root.notifs.slice(Config.notifs.groupPreviewNum) - } - - NotifLine {} - } - } - - Behavior on opacity { - Anim {} - } - } - } - } - - Behavior on implicitHeight { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - component NotifLine: StyledText { - id: notifLine - - required property Notifs.Notif modelData - - Layout.fillWidth: true - textFormat: Text.MarkdownText - text: { - const summary = modelData.summary.replace(/\n/g, " "); - const body = modelData.body.replace(/\n/g, " "); - const colour = root.urgency === "critical" ? Colours.palette.m3secondary : Colours.palette.m3outline; - - if (metrics.text === metrics.elidedText) - return `${summary} <span style='color:${colour}'>${body}</span>`; - - const t = metrics.elidedText.length - 3; - if (t < summary.length) - return `${summary.slice(0, t)}...`; - - return `${summary} <span style='color:${colour}'>${body.slice(0, t - summary.length)}...</span>`; - } - color: root.urgency === "critical" ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface - - Component.onCompleted: modelData.lock(this) - Component.onDestruction: modelData.unlock(this) - - TextMetrics { - id: metrics - - text: `${notifLine.modelData.summary} ${notifLine.modelData.body}`.replace(/\n/g, " ") - font.pointSize: notifLine.font.pointSize - font.family: notifLine.font.family - elideWidth: notifLine.width - elide: Text.ElideRight - } - } -} diff --git a/modules/lock/WeatherInfo.qml b/modules/lock/WeatherInfo.qml deleted file mode 100644 index d6c25af..0000000 --- a/modules/lock/WeatherInfo.qml +++ /dev/null @@ -1,176 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.services -import qs.config -import qs.utils -import QtQuick -import QtQuick.Layouts - -ColumnLayout { - id: root - - required property int rootHeight - - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Appearance.padding.large * 2 - - spacing: Appearance.spacing.small - - Loader { - Layout.topMargin: Appearance.padding.large * 2 - Layout.bottomMargin: -Appearance.padding.large - Layout.alignment: Qt.AlignHCenter - - active: root.rootHeight > 610 - visible: active - - sourceComponent: StyledText { - text: qsTr("Weather") - color: Colours.palette.m3primary - font.pointSize: Appearance.font.size.extraLarge - font.weight: 500 - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.large - - MaterialIcon { - animate: true - text: Weather.icon - color: Colours.palette.m3secondary - font.pointSize: Appearance.font.size.extraLarge * 2.5 - } - - ColumnLayout { - spacing: Appearance.spacing.small - - StyledText { - Layout.fillWidth: true - - animate: true - text: Weather.description - color: Colours.palette.m3secondary - font.pointSize: Appearance.font.size.large - font.weight: 500 - elide: Text.ElideRight - } - - StyledText { - Layout.fillWidth: true - - animate: true - text: qsTr("Humidity: %1%").arg(Weather.humidity) - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.normal - elide: Text.ElideRight - } - } - - Loader { - Layout.rightMargin: Appearance.padding.smaller - active: root.width > 400 - visible: active - - sourceComponent: ColumnLayout { - spacing: Appearance.spacing.small - - StyledText { - Layout.fillWidth: true - - animate: true - text: Weather.temp - color: Colours.palette.m3primary - horizontalAlignment: Text.AlignRight - font.pointSize: Appearance.font.size.extraLarge - font.weight: 500 - elide: Text.ElideLeft - } - - StyledText { - Layout.fillWidth: true - - animate: true - text: qsTr("Feels like: %1").arg(Weather.feelsLike) - color: Colours.palette.m3outline - horizontalAlignment: Text.AlignRight - font.pointSize: Appearance.font.size.smaller - elide: Text.ElideLeft - } - } - } - } - - Loader { - id: forecastLoader - - Layout.topMargin: Appearance.spacing.smaller - Layout.bottomMargin: Appearance.padding.large * 2 - Layout.fillWidth: true - - active: root.rootHeight > 820 - visible: active - - sourceComponent: RowLayout { - spacing: Appearance.spacing.large - - Repeater { - model: { - const forecast = Weather.hourlyForecast; - const count = root.width < 320 ? 3 : root.width < 400 ? 4 : 5; - if (!forecast) - return Array.from({ - length: count - }, () => null); - - return forecast.slice(0, count); - } - - ColumnLayout { - id: forecastHour - - required property var modelData - - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - Layout.fillWidth: true - text: { - const hour = forecastHour.modelData?.hour ?? 0; - return hour > 12 ? `${(hour - 12).toString().padStart(2, "0")} PM` : `${hour.toString().padStart(2, "0")} AM`; - } - color: Colours.palette.m3outline - horizontalAlignment: Text.AlignHCenter - font.pointSize: Appearance.font.size.larger - } - - MaterialIcon { - Layout.alignment: Qt.AlignHCenter - text: forecastHour.modelData?.icon ?? "cloud_alert" - font.pointSize: Appearance.font.size.extraLarge * 1.5 - font.weight: 500 - } - - StyledText { - Layout.alignment: Qt.AlignHCenter - text: Config.services.useFahrenheit ? `${forecastHour.modelData?.tempF ?? 0}°F` : `${forecastHour.modelData?.tempC ?? 0}°C` - color: Colours.palette.m3secondary - font.pointSize: Appearance.font.size.larger - } - } - } - } - } - - Timer { - running: true - triggeredOnStart: true - repeat: true - interval: 900000 // 15 minutes - onTriggered: Weather.reload() - } -} diff --git a/modules/utilities/RecordingDeleteModal.qml b/modules/utilities/RecordingDeleteModal.qml deleted file mode 100644 index 127afe9..0000000 --- a/modules/utilities/RecordingDeleteModal.qml +++ /dev/null @@ -1,207 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.controls -import qs.components.effects -import qs.services -import qs.config -import Caelestia -import QtQuick -import QtQuick.Layouts -import QtQuick.Shapes - -Loader { - id: root - - required property var props - - anchors.fill: parent - - opacity: root.props.recordingConfirmDelete ? 1 : 0 - active: opacity > 0 - - sourceComponent: MouseArea { - id: deleteConfirmation - - property string path - - Component.onCompleted: path = root.props.recordingConfirmDelete - - hoverEnabled: true - onClicked: root.props.recordingConfirmDelete = "" - - Item { - anchors.fill: parent - anchors.margins: -Appearance.padding.large - anchors.rightMargin: -Appearance.padding.large - Config.border.thickness - anchors.bottomMargin: -Appearance.padding.large - Config.border.thickness - opacity: 0.5 - - StyledRect { - anchors.fill: parent - topLeftRadius: Config.border.rounding - color: Colours.palette.m3scrim - } - - Shape { - id: shape - - anchors.fill: parent - preferredRendererType: Shape.CurveRenderer - asynchronous: true - - ShapePath { - startX: -Config.border.rounding * 2 - startY: shape.height - Config.border.thickness - strokeWidth: 0 - fillGradient: LinearGradient { - orientation: LinearGradient.Horizontal - x1: -Config.border.rounding * 2 - - GradientStop { - position: 0 - color: Qt.alpha(Colours.palette.m3scrim, 0) - } - GradientStop { - position: 1 - color: Colours.palette.m3scrim - } - } - - PathLine { - relativeX: Config.border.rounding - relativeY: 0 - } - PathArc { - relativeY: -Config.border.rounding - radiusX: Config.border.rounding - radiusY: Config.border.rounding - direction: PathArc.Counterclockwise - } - PathLine { - relativeX: 0 - relativeY: Config.border.rounding + Config.border.thickness - } - PathLine { - relativeX: -Config.border.rounding * 2 - relativeY: 0 - } - } - - ShapePath { - startX: shape.width - Config.border.rounding - Config.border.thickness - strokeWidth: 0 - fillGradient: LinearGradient { - orientation: LinearGradient.Vertical - y1: -Config.border.rounding * 2 - - GradientStop { - position: 0 - color: Qt.alpha(Colours.palette.m3scrim, 0) - } - GradientStop { - position: 1 - color: Colours.palette.m3scrim - } - } - - PathArc { - relativeX: Config.border.rounding - relativeY: -Config.border.rounding - radiusX: Config.border.rounding - radiusY: Config.border.rounding - direction: PathArc.Counterclockwise - } - PathLine { - relativeX: 0 - relativeY: -Config.border.rounding - } - PathLine { - relativeX: Config.border.thickness - relativeY: 0 - } - PathLine { - relativeX: 0 - } - } - } - } - - StyledRect { - anchors.centerIn: parent - radius: Appearance.rounding.large - color: Colours.palette.m3surfaceContainerHigh - - scale: 0 - Component.onCompleted: scale = Qt.binding(() => root.props.recordingConfirmDelete ? 1 : 0) - - width: Math.min(parent.width - Appearance.padding.large * 2, implicitWidth) - implicitWidth: deleteConfirmationLayout.implicitWidth + Appearance.padding.large * 3 - implicitHeight: deleteConfirmationLayout.implicitHeight + Appearance.padding.large * 3 - - MouseArea { - anchors.fill: parent - } - - Elevation { - anchors.fill: parent - radius: parent.radius - z: -1 - level: 3 - } - - ColumnLayout { - id: deleteConfirmationLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large * 1.5 - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Delete recording?") - font.pointSize: Appearance.font.size.large - } - - StyledText { - Layout.fillWidth: true - text: qsTr("Recording '%1' will be permanently deleted.").arg(deleteConfirmation.path) - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.small - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - } - - RowLayout { - Layout.topMargin: Appearance.spacing.normal - Layout.alignment: Qt.AlignRight - spacing: Appearance.spacing.normal - - TextButton { - text: qsTr("Cancel") - type: TextButton.Text - onClicked: root.props.recordingConfirmDelete = "" - } - - TextButton { - text: qsTr("Delete") - type: TextButton.Text - onClicked: { - CUtils.deleteFile(Qt.resolvedUrl(root.props.recordingConfirmDelete)); - root.props.recordingConfirmDelete = ""; - } - } - } - } - - Behavior on scale { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - } - } - - Behavior on opacity { - Anim {} - } -} diff --git a/modules/utilities/cards/RecordingList.qml b/modules/utilities/cards/RecordingList.qml deleted file mode 100644 index b9d757a..0000000 --- a/modules/utilities/cards/RecordingList.qml +++ /dev/null @@ -1,241 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.components.controls -import qs.components.containers -import qs.services -import qs.config -import qs.utils -import Caelestia -import Caelestia.Models -import Quickshell -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts - -ColumnLayout { - id: root - - required property var props - required property var visibilities - - spacing: 0 - - WrapperMouseArea { - Layout.fillWidth: true - - cursorShape: Qt.PointingHandCursor - onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded - - RowLayout { - spacing: Appearance.spacing.smaller - - MaterialIcon { - Layout.alignment: Qt.AlignVCenter - text: "list" - font.pointSize: Appearance.font.size.large - } - - StyledText { - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - text: qsTr("Recordings") - font.pointSize: Appearance.font.size.normal - } - - IconButton { - icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more" - type: IconButton.Text - label.animate: true - onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded - } - } - } - - StyledListView { - id: list - - model: FileSystemModel { - path: Paths.recsdir - nameFilters: ["recording_*.mp4"] - sortReverse: true - } - - Layout.fillWidth: true - Layout.rightMargin: -Appearance.spacing.small - implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3) - clip: true - - StyledScrollBar.vertical: StyledScrollBar { - flickable: list - } - - delegate: RowLayout { - id: recording - - required property FileSystemEntry modelData - property string baseName - - anchors.left: list.contentItem.left - anchors.right: list.contentItem.right - anchors.rightMargin: Appearance.spacing.small - spacing: Appearance.spacing.small / 2 - - Component.onCompleted: baseName = modelData.baseName - - StyledText { - Layout.fillWidth: true - Layout.rightMargin: Appearance.spacing.small / 2 - text: { - const time = recording.baseName; - const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/); - if (!matches) - return time; - const date = new Date(...matches.slice(1)); - date.setMonth(date.getMonth() - 1); // Woe (months start from 0) - return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale())); - } - color: Colours.palette.m3onSurfaceVariant - elide: Text.ElideRight - } - - IconButton { - icon: "play_arrow" - type: IconButton.Text - onClicked: { - root.visibilities.utilities = false; - root.visibilities.sidebar = false; - Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]); - } - } - - IconButton { - icon: "folder" - type: IconButton.Text - onClicked: { - root.visibilities.utilities = false; - root.visibilities.sidebar = false; - Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]); - } - } - - IconButton { - icon: "delete_forever" - type: IconButton.Text - label.color: Colours.palette.m3error - stateLayer.color: Colours.palette.m3error - onClicked: root.props.recordingConfirmDelete = recording.modelData.path - } - } - - add: Transition { - Anim { - property: "opacity" - from: 0 - to: 1 - } - Anim { - property: "scale" - from: 0.5 - to: 1 - } - } - - remove: Transition { - Anim { - property: "opacity" - to: 0 - } - Anim { - property: "scale" - to: 0.5 - } - } - - displaced: Transition { - Anim { - properties: "opacity,scale" - to: 1 - } - Anim { - property: "y" - } - } - - Loader { - anchors.centerIn: parent - - opacity: list.count === 0 ? 1 : 0 - active: opacity > 0 - - sourceComponent: ColumnLayout { - spacing: Appearance.spacing.small - - MaterialIcon { - Layout.alignment: Qt.AlignHCenter - text: "scan_delete" - color: Colours.palette.m3outline - font.pointSize: Appearance.font.size.extraLarge - - opacity: root.props.recordingListExpanded ? 1 : 0 - scale: root.props.recordingListExpanded ? 1 : 0 - Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0 - - Behavior on opacity { - Anim {} - } - - Behavior on scale { - Anim {} - } - - Behavior on Layout.preferredHeight { - Anim {} - } - } - - RowLayout { - spacing: Appearance.spacing.smaller - - MaterialIcon { - Layout.alignment: Qt.AlignHCenter - text: "scan_delete" - color: Colours.palette.m3outline - - opacity: !root.props.recordingListExpanded ? 1 : 0 - scale: !root.props.recordingListExpanded ? 1 : 0 - Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0 - - Behavior on opacity { - Anim {} - } - - Behavior on scale { - Anim {} - } - - Behavior on Layout.preferredWidth { - Anim {} - } - } - - StyledText { - text: qsTr("No recordings found") - color: Colours.palette.m3outline - } - } - } - - Behavior on opacity { - Anim {} - } - } - - Behavior on implicitHeight { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - } -} |