From c1510b547645de5e8f70f6be99a0ba894b797241 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Wed, 12 Nov 2025 14:51:22 -0500 Subject: notifs/toasts: reworked notifications and toasts and how they display and work together. see pull request comment. --- modules/utilities/toasts/ToastItem.qml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'modules/utilities') diff --git a/modules/utilities/toasts/ToastItem.qml b/modules/utilities/toasts/ToastItem.qml index f475500..477a23c 100644 --- a/modules/utilities/toasts/ToastItem.qml +++ b/modules/utilities/toasts/ToastItem.qml @@ -28,14 +28,13 @@ StyledRect { border.width: 1 border.color: { - let colour = Colours.palette.m3outlineVariant; if (root.modelData.type === Toast.Success) - colour = Colours.palette.m3success; + return Colours.palette.m3success; if (root.modelData.type === Toast.Warning) - colour = Colours.palette.m3secondaryContainer; + return Colours.palette.m3secondaryContainer; if (root.modelData.type === Toast.Error) - colour = Colours.palette.m3error; - return Qt.alpha(colour, 0.3); + return Colours.palette.m3error; + return Colours.palette.m3outlineVariant; } Elevation { -- cgit v1.2.3-freya From ffe14748a2cf5bc5710fe24d0ccae80b8437f35d Mon Sep 17 00:00:00 2001 From: ATMDA Date: Wed, 12 Nov 2025 20:57:38 -0500 Subject: notifs/toasts: reverted all changes to notifications to c0ea060f --- modules/drawers/Panels.qml | 88 ------------- modules/lock/NotifDock.qml | 4 +- modules/lock/NotifGroup.qml | 2 +- modules/notifications/AppIconBadge.qml | 57 -------- modules/notifications/Content.qml | 58 +-------- modules/notifications/Notification.qml | 72 +++++++---- modules/notifications/NotificationToast.qml | 120 ----------------- modules/notifications/NotificationToasts.qml | 186 --------------------------- modules/notifications/Wrapper.qml | 2 - modules/utilities/toasts/ToastItem.qml | 9 +- services/Notifs.qml | 72 +---------- 11 files changed, 61 insertions(+), 609 deletions(-) delete mode 100644 modules/notifications/AppIconBadge.qml delete mode 100644 modules/notifications/NotificationToast.qml delete mode 100644 modules/notifications/NotificationToasts.qml (limited to 'modules/utilities') diff --git a/modules/drawers/Panels.qml b/modules/drawers/Panels.qml index 8b5a251..4ce1182 100644 --- a/modules/drawers/Panels.qml +++ b/modules/drawers/Panels.qml @@ -8,10 +8,6 @@ import qs.modules.bar.popouts as BarPopouts import qs.modules.utilities as Utilities import qs.modules.utilities.toasts as Toasts import qs.modules.sidebar as Sidebar -import qs.components -import qs.components.controls -import qs.components.effects -import qs.services import Quickshell import QtQuick @@ -31,7 +27,6 @@ Item { readonly property alias utilities: utilities readonly property alias toasts: toasts readonly property alias sidebar: sidebar - readonly property alias clearAllButton: clearAllButton anchors.fill: parent anchors.margins: Config.border.thickness @@ -59,89 +54,6 @@ Item { anchors.right: parent.right } - // Clear all notifications button - positioned to the left of the notification panel - Item { - id: clearAllButton - - readonly property bool hasNotifications: Notifs.notClosed.length > 0 - readonly property bool panelVisible: notifications.height > 0 || notifications.implicitHeight > 0 - readonly property bool shouldShow: hasNotifications && panelVisible - - anchors.top: notifications.top - anchors.right: notifications.left - anchors.rightMargin: Appearance.padding.normal - anchors.topMargin: Appearance.padding.large - - width: button.implicitWidth - height: button.implicitHeight - enabled: shouldShow - - IconButton { - id: button - - icon: "clear_all" - radius: Appearance.rounding.normal - padding: Appearance.padding.normal - font.pointSize: Math.round(Appearance.font.size.large * 1.2) - - onClicked: { - // Clear all notifications - for (const notif of Notifs.list.slice()) - notif.close(); - } - - Elevation { - anchors.fill: parent - radius: parent.radius - z: -1 - level: button.stateLayer.containsMouse ? 4 : 3 - } - } - - // Keep notification panel visible when hovering over the button - MouseArea { - anchors.fill: button - hoverEnabled: true - acceptedButtons: Qt.NoButton - onEntered: { - if (notifications.content && Notifs.notClosed.length > 0) { - notifications.content.show(); - } - } - onExited: { - // Panel will be hidden by Interactions.qml if mouse is not over panel or button - } - } - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - Behavior on scale { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - opacity: shouldShow ? 1 : 0 - scale: shouldShow ? 1 : 0.5 - } - - Notifications.NotificationToasts { - id: notificationToasts - - panels: root - - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Config.border.thickness - anchors.rightMargin: Config.border.thickness - } - Session.Wrapper { id: session diff --git a/modules/lock/NotifDock.qml b/modules/lock/NotifDock.qml index db087bd..7551e68 100644 --- a/modules/lock/NotifDock.qml +++ b/modules/lock/NotifDock.qml @@ -22,7 +22,7 @@ ColumnLayout { StyledText { Layout.fillWidth: true - text: Notifs.notClosed.length > 0 ? qsTr("%1 notification%2").arg(Notifs.notClosed.length).arg(Notifs.notClosed.length === 1 ? "" : "s") : qsTr("Notifications") + 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 @@ -42,7 +42,7 @@ ColumnLayout { anchors.centerIn: parent asynchronous: true active: opacity > 0 - opacity: Notifs.notClosed.length > 0 ? 0 : 1 + opacity: Notifs.list.length > 0 ? 0 : 1 sourceComponent: ColumnLayout { spacing: Appearance.spacing.large diff --git a/modules/lock/NotifGroup.qml b/modules/lock/NotifGroup.qml index 50b14ae..2a08c26 100644 --- a/modules/lock/NotifGroup.qml +++ b/modules/lock/NotifGroup.qml @@ -16,7 +16,7 @@ StyledRect { required property string modelData - readonly property list notifs: Notifs.notClosed.filter(notif => notif.appName === modelData) + readonly property list 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" diff --git a/modules/notifications/AppIconBadge.qml b/modules/notifications/AppIconBadge.qml deleted file mode 100644 index 286522f..0000000 --- a/modules/notifications/AppIconBadge.qml +++ /dev/null @@ -1,57 +0,0 @@ -import qs.components -import qs.components.effects -import qs.services -import qs.config -import qs.utils -import Quickshell -import Quickshell.Services.Notifications -import QtQuick - -StyledRect { - id: root - - required property Notifs.Notif modelData - required property bool hasImage - required property bool hasAppIcon - - radius: Appearance.rounding.full - color: modelData.getBadgeBackgroundColor() - implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image - implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image - - Loader { - id: icon - - active: root.hasAppIcon - asynchronous: false - visible: active - - anchors.centerIn: parent - - width: Math.round(parent.width * 0.6) - height: Math.round(parent.width * 0.6) - - sourceComponent: ColouredIcon { - anchors.fill: parent - source: Quickshell.iconPath(root.modelData.appIcon) - colour: root.modelData.getIconColor() - layer.enabled: root.modelData.appIcon.endsWith("symbolic") - } - } - - Loader { - active: !root.hasAppIcon - asynchronous: false - visible: active - anchors.centerIn: parent - anchors.horizontalCenterOffset: -Appearance.font.size.large * 0.02 - anchors.verticalCenterOffset: Appearance.font.size.large * 0.02 - - sourceComponent: MaterialIcon { - text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency) - color: root.modelData.getIconColor() - font.pointSize: Appearance.font.size.large - } - } -} - diff --git a/modules/notifications/Content.qml b/modules/notifications/Content.qml index 035a228..2d4590e 100644 --- a/modules/notifications/Content.qml +++ b/modules/notifications/Content.qml @@ -13,8 +13,6 @@ Item { required property Item panels readonly property int padding: Appearance.padding.large - property bool shouldShow: false - anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right @@ -22,16 +20,13 @@ Item { implicitWidth: Config.notifs.sizes.width + padding * 2 implicitHeight: { const count = list.count; - if (count === 0 || !shouldShow) + if (count === 0) return 0; let height = (count - 1) * Appearance.spacing.smaller; for (let i = 0; i < count; i++) height += list.itemAtIndex(i)?.nonAnimHeight ?? 0; - const screenHeight = QsWindow.window?.screen?.height ?? 0; - const maxHeight = Math.floor(screenHeight * 0.45); - if (visibilities && panels) { if (visibilities.osd) { const h = panels.osd.y - Config.border.rounding * 2 - padding * 2; @@ -46,8 +41,7 @@ Item { } } - const availableHeight = Math.min(maxHeight, screenHeight - Config.border.thickness * 2); - return Math.min(availableHeight, height + padding * 2); + return Math.min((QsWindow.window?.screen?.height ?? 0) - Config.border.thickness * 2, height + padding * 2); } ClippingWrapperRectangle { @@ -61,7 +55,7 @@ Item { id: list model: ScriptModel { - values: [...Notifs.notClosed] + values: Notifs.popups.filter(n => !n.closed) } anchors.fill: parent @@ -198,52 +192,6 @@ Item { } } - Timer { - id: hideTimer - - interval: 5000 - onTriggered: { - if (list.count > 0) - root.shouldShow = false; - } - } - - function show(): void { - if (list.count > 0) { - shouldShow = true; - hideTimer.restart(); - } - } - - Connections { - target: list - - function onCountChanged(): void { - if (list.count === 0) { - root.shouldShow = false; - hideTimer.stop(); - } - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton - onEntered: { - if (list.count > 0) { - root.shouldShow = true; - hideTimer.restart(); - } - } - onExited: { - if (list.count > 0) { - root.shouldShow = false; - hideTimer.stop(); - } - } - } - Behavior on implicitHeight { Anim {} } diff --git a/modules/notifications/Notification.qml b/modules/notifications/Notification.qml index bc5c086..95507fc 100644 --- a/modules/notifications/Notification.qml +++ b/modules/notifications/Notification.qml @@ -17,31 +17,22 @@ StyledRect { required property Notifs.Notif modelData readonly property bool hasImage: modelData.image.length > 0 readonly property bool hasAppIcon: modelData.appIcon.length > 0 - readonly property int nonAnimHeight: { - const baseHeight = summary.implicitHeight + inner.anchors.margins * 2; - return root.expanded - ? baseHeight + appName.height + body.height + actions.height + actions.anchors.topMargin - : baseHeight + bodyPreview.height; - } + readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2 property bool expanded - property bool disableSlideIn: false - color: modelData.getBackgroundColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainer radius: Appearance.rounding.normal implicitWidth: Config.notifs.sizes.width implicitHeight: inner.implicitHeight - x: disableSlideIn ? 0 : Config.notifs.sizes.width + x: Config.notifs.sizes.width Component.onCompleted: { - if (!root.disableSlideIn) { - x = 0; - } + x = 0; modelData.lock(this); } Component.onDestruction: modelData.unlock(this) Behavior on x { - enabled: !disableSlideIn Anim { easing.bezierCurve: Appearance.anim.curves.emphasizedDecel } @@ -143,18 +134,53 @@ StyledRect { Loader { id: appIcon - active: !root.hasImage || root.hasAppIcon - asynchronous: false + active: root.hasAppIcon || !root.hasImage + asynchronous: true anchors.horizontalCenter: root.hasImage ? undefined : image.horizontalCenter anchors.verticalCenter: root.hasImage ? undefined : image.verticalCenter anchors.right: root.hasImage ? image.right : undefined anchors.bottom: root.hasImage ? image.bottom : undefined - sourceComponent: AppIconBadge { - modelData: root.modelData - hasImage: root.hasImage - hasAppIcon: root.hasAppIcon + sourceComponent: StyledRect { + radius: Appearance.rounding.full + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? Colours.layer(Colours.palette.m3surfaceContainerHighest, 2) : Colours.palette.m3secondaryContainer + implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + + Loader { + id: icon + + active: root.hasAppIcon + asynchronous: true + + anchors.centerIn: parent + + width: Math.round(parent.width * 0.6) + height: Math.round(parent.width * 0.6) + + sourceComponent: ColouredIcon { + anchors.fill: parent + source: Quickshell.iconPath(root.modelData.appIcon) + colour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + layer.enabled: root.modelData.appIcon.endsWith("symbolic") + } + } + + Loader { + active: !root.hasAppIcon + asynchronous: true + anchors.centerIn: parent + anchors.horizontalCenterOffset: -Appearance.font.size.large * 0.02 + anchors.verticalCenterOffset: Appearance.font.size.large * 0.02 + + sourceComponent: MaterialIcon { + text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency) + + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } } } @@ -296,7 +322,7 @@ StyledRect { StateLayer { radius: Appearance.rounding.full - color: root.modelData.getStateLayerColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface function onClicked() { root.expanded = !root.expanded; @@ -417,7 +443,7 @@ StyledRect { required property var modelData radius: Appearance.rounding.full - color: root.modelData.getActionBackgroundColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondary : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) Layout.preferredWidth: actionText.width + Appearance.padding.normal * 2 Layout.preferredHeight: actionText.height + Appearance.padding.small * 2 @@ -426,7 +452,7 @@ StyledRect { StateLayer { radius: Appearance.rounding.full - color: root.modelData.getStateLayerColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurface function onClicked(): void { action.modelData.invoke(); @@ -438,7 +464,7 @@ StyledRect { anchors.centerIn: parent text: actionTextMetrics.elidedText - color: root.modelData.getActionTextColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurfaceVariant font.pointSize: Appearance.font.size.small } diff --git a/modules/notifications/NotificationToast.qml b/modules/notifications/NotificationToast.qml deleted file mode 100644 index 90414fe..0000000 --- a/modules/notifications/NotificationToast.qml +++ /dev/null @@ -1,120 +0,0 @@ -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 Notifs.Notif modelData - - readonly property bool hasImage: modelData.image.length > 0 - readonly property bool hasAppIcon: modelData.appIcon.length > 0 - - anchors.left: parent.left - anchors.right: parent.right - implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2 - - radius: Appearance.rounding.normal - color: Colours.palette.m3surface - - border.width: 1 - border.color: Colours.palette.m3outlineVariant - - Elevation { - anchors.fill: parent - radius: parent.radius - opacity: parent.opacity - z: -1 - level: 3 - } - - RowLayout { - id: layout - - anchors.fill: parent - anchors.margins: Appearance.padding.smaller - anchors.leftMargin: Appearance.padding.normal - anchors.rightMargin: Appearance.padding.normal - spacing: Appearance.spacing.normal - - Item { - Layout.preferredWidth: Config.notifs.sizes.image - Layout.preferredHeight: Config.notifs.sizes.image - - Loader { - id: imageLoader - - active: root.hasImage - asynchronous: true - anchors.fill: parent - - sourceComponent: ClippingRectangle { - radius: Appearance.rounding.full - implicitWidth: Config.notifs.sizes.image - implicitHeight: Config.notifs.sizes.image - - Image { - anchors.fill: parent - source: Qt.resolvedUrl(root.modelData.image) - fillMode: Image.PreserveAspectCrop - cache: false - asynchronous: true - } - } - } - - Loader { - id: appIconLoader - - active: root.hasAppIcon || !root.hasImage - asynchronous: true - - anchors.horizontalCenter: root.hasImage ? undefined : parent.horizontalCenter - anchors.verticalCenter: root.hasImage ? undefined : parent.verticalCenter - anchors.right: root.hasImage ? parent.right : undefined - anchors.bottom: root.hasImage ? parent.bottom : undefined - - sourceComponent: AppIconBadge { - modelData: root.modelData - hasImage: root.hasImage - hasAppIcon: root.hasAppIcon - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: 0 - - StyledText { - id: title - - Layout.fillWidth: true - text: root.modelData.summary - color: Colours.palette.m3onSurface - font.pointSize: Appearance.font.size.normal - elide: Text.ElideRight - } - - StyledText { - Layout.fillWidth: true - textFormat: Text.StyledText - text: root.modelData.body - color: Colours.palette.m3onSurface - opacity: 0.8 - elide: Text.ElideRight - } - } - } - - Behavior on border.color { - CAnim {} - } -} diff --git a/modules/notifications/NotificationToasts.qml b/modules/notifications/NotificationToasts.qml deleted file mode 100644 index 96fe817..0000000 --- a/modules/notifications/NotificationToasts.qml +++ /dev/null @@ -1,186 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.config -import qs.services -import Quickshell -import Quickshell.Widgets -import QtQuick - -Item { - id: root - - required property Item panels - - readonly property int spacing: Appearance.spacing.small - readonly property int maxToasts: 5 - readonly property bool listVisible: panels.notifications.content.shouldShow - - property bool flag - property var activeToasts: new Set() - - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Appearance.padding.normal - - implicitWidth: Config.notifs.sizes.width - implicitHeight: { - if (listVisible) - return 0; - - let height = -spacing; - for (let i = 0; i < repeater.count; i++) { - const item = repeater.itemAt(i) as ToastWrapper; - if (item && !item.modelData.closed && !item.previewHidden) - height += item.implicitHeight + spacing; - } - return height; - } - - opacity: listVisible ? 0 : 1 - visible: opacity > 0 - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - } - } - - Repeater { - id: repeater - - model: ScriptModel { - values: { - const toasts = []; - let visibleCount = 0; - - for (const notif of Notifs.list) { - if (notif.showAsToast) { - root.activeToasts.add(notif); - } - if (notif.closed) { - root.activeToasts.delete(notif); - } - } - - for (const notif of Notifs.list) { - if (root.activeToasts.has(notif)) { - toasts.push(notif); - if (notif.showAsToast && !notif.closed) { - visibleCount++; - if (visibleCount > root.maxToasts) - break; - } - } - } - return toasts; - } - onValuesChanged: root.flagChanged() - } - - ToastWrapper {} - } - - component ToastWrapper: MouseArea { - id: toast - - required property int index - required property Notifs.Notif modelData - - readonly property bool previewHidden: { - let extraHidden = 0; - for (let i = 0; i < index; i++) { - const item = repeater.itemAt(i); - if (item && item.modelData.closed) - extraHidden++; - } - return index >= root.maxToasts + extraHidden; - } - - opacity: modelData.closed || previewHidden || !modelData.showAsToast ? 0 : 1 - scale: modelData.closed || previewHidden || !modelData.showAsToast ? 0.7 : 1 - - anchors.topMargin: { - root.flag; - let margin = 0; - for (let i = 0; i < index; i++) { - const item = repeater.itemAt(i) as ToastWrapper; - if (item && !item.modelData.closed && !item.previewHidden) - margin += item.implicitHeight + root.spacing; - } - return margin; - } - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - implicitHeight: toastInner.implicitHeight - - acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton - onClicked: { - modelData.showAsToast = false; - modelData.close(); - } - - Component.onCompleted: modelData.lock(this) - - onPreviewHiddenChanged: { - if (initAnim.running && previewHidden) - initAnim.stop(); - } - - Anim { - id: initAnim - - Component.onCompleted: running = !toast.previewHidden - - target: toast - properties: "opacity,scale" - from: 0 - to: 1 - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - - ParallelAnimation { - running: toast.modelData.closed || (!toast.modelData.showAsToast && !toast.modelData.closed) - onStarted: toast.anchors.topMargin = toast.anchors.topMargin - onFinished: { - if (toast.modelData.closed) - toast.modelData.unlock(toast); - } - - Anim { - target: toast - property: "opacity" - to: 0 - } - Anim { - target: toast - property: "scale" - to: 0.7 - } - } - - NotificationToast { - id: toastInner - - modelData: toast.modelData - } - - Behavior on opacity { - Anim {} - } - - Behavior on scale { - Anim {} - } - - Behavior on anchors.topMargin { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - } -} diff --git a/modules/notifications/Wrapper.qml b/modules/notifications/Wrapper.qml index 4b54883..61acc56 100644 --- a/modules/notifications/Wrapper.qml +++ b/modules/notifications/Wrapper.qml @@ -8,8 +8,6 @@ Item { required property var visibilities required property Item panels - readonly property alias content: content - visible: height > 0 implicitWidth: Math.max(panels.sidebar.width, content.implicitWidth) implicitHeight: content.implicitHeight diff --git a/modules/utilities/toasts/ToastItem.qml b/modules/utilities/toasts/ToastItem.qml index 477a23c..f475500 100644 --- a/modules/utilities/toasts/ToastItem.qml +++ b/modules/utilities/toasts/ToastItem.qml @@ -28,13 +28,14 @@ StyledRect { border.width: 1 border.color: { + let colour = Colours.palette.m3outlineVariant; if (root.modelData.type === Toast.Success) - return Colours.palette.m3success; + colour = Colours.palette.m3success; if (root.modelData.type === Toast.Warning) - return Colours.palette.m3secondaryContainer; + colour = Colours.palette.m3secondaryContainer; if (root.modelData.type === Toast.Error) - return Colours.palette.m3error; - return Colours.palette.m3outlineVariant; + colour = Colours.palette.m3error; + return Qt.alpha(colour, 0.3); } Elevation { diff --git a/services/Notifs.qml b/services/Notifs.qml index 82ed8c4..4a89c7f 100644 --- a/services/Notifs.qml +++ b/services/Notifs.qml @@ -77,10 +77,8 @@ Singleton { onNotification: notif => { notif.tracked = true; - const shouldShowAsToast = !props.dnd && ![...Visibilities.screens.values()].some(v => v.sidebar); const comp = notifComp.createObject(root, { - popup: shouldShowAsToast, - showAsToast: shouldShowAsToast, + popup: !props.dnd && ![...Visibilities.screens.values()].some(v => v.sidebar), notification: notif }); root.list = [comp, ...root.list]; @@ -145,7 +143,6 @@ Singleton { property bool popup property bool closed - property bool showAsToast: false property var locks: new Set() property date time: new Date() @@ -179,74 +176,7 @@ Singleton { property bool hasActionIcons property list actions - readonly property bool isCritical: urgency === NotificationUrgency.Critical - readonly property bool isLow: urgency === NotificationUrgency.Low - - function getBackgroundColor(): color { - if (isCritical) return Colours.palette.m3secondaryContainer; - return Colours.tPalette.m3surfaceContainer; - } - - function getBadgeBackgroundColor(): color { - if (isCritical) return Colours.palette.m3error; - if (isLow) return Colours.layer(Colours.palette.m3surfaceContainerHighest, 2); - return Colours.palette.m3secondaryContainer; - } - - function getIconColor(): color { - if (isCritical) return Colours.palette.m3onError; - if (isLow) return Colours.palette.m3onSurface; - return Colours.palette.m3onSecondaryContainer; - } - - function getStateLayerColor(): color { - if (isCritical) return Colours.palette.m3onSecondaryContainer; - return Colours.palette.m3onSurface; - } - - function getActionBackgroundColor(): color { - if (isCritical) return Colours.palette.m3secondary; - return Colours.layer(Colours.palette.m3surfaceContainerHigh, 2); - } - - function getActionTextColor(): color { - if (isCritical) return Colours.palette.m3onSecondary; - return Colours.palette.m3onSurfaceVariant; - } - readonly property Timer timer: Timer { - id: toastTimer - - running: notif.showAsToast - interval: { - let timeout = notif.expireTimeout; - if (timeout <= 0) { - switch (notif.urgency) { - case NotificationUrgency.Critical: - timeout = 10000; - break; - case NotificationUrgency.Normal: - timeout = 5000; - break; - case NotificationUrgency.Low: - timeout = 5000; - break; - default: - timeout = 5000; - } - } - return timeout; - } - onTriggered: { - if (Config.notifs.expire) - notif.popup = false; - if (notif.showAsToast) { - notif.showAsToast = false; - } - } - } - - readonly property Timer popupTimer: Timer { running: true interval: notif.expireTimeout > 0 ? notif.expireTimeout : Config.notifs.defaultExpireTimeout onTriggered: { -- cgit v1.2.3-freya From baa10d6ccfe8ad03a8832c4a43179c21020997ab Mon Sep 17 00:00:00 2001 From: ATMDA Date: Thu, 13 Nov 2025 16:56:49 -0500 Subject: controlcenter: created dev panel for wireless testing --- modules/controlcenter/dev/DevControlCenter.qml | 94 ++++++++++++ modules/controlcenter/dev/DevDebugPane.qml | 170 ++++++++++++++++++++++ modules/controlcenter/dev/DevNavRail.qml | 194 +++++++++++++++++++++++++ modules/controlcenter/dev/DevPanes.qml | 70 +++++++++ modules/controlcenter/dev/DevSession.qml | 23 +++ modules/controlcenter/dev/DevWindowFactory.qml | 62 ++++++++ modules/controlcenter/dev/DevWindowTitle.qml | 53 +++++++ modules/controlcenter/dev/DevWirelessPane.qml | 68 +++++++++ modules/utilities/cards/Toggles.qml | 13 ++ 9 files changed, 747 insertions(+) create mode 100644 modules/controlcenter/dev/DevControlCenter.qml create mode 100644 modules/controlcenter/dev/DevDebugPane.qml create mode 100644 modules/controlcenter/dev/DevNavRail.qml create mode 100644 modules/controlcenter/dev/DevPanes.qml create mode 100644 modules/controlcenter/dev/DevSession.qml create mode 100644 modules/controlcenter/dev/DevWindowFactory.qml create mode 100644 modules/controlcenter/dev/DevWindowTitle.qml create mode 100644 modules/controlcenter/dev/DevWirelessPane.qml (limited to 'modules/utilities') diff --git a/modules/controlcenter/dev/DevControlCenter.qml b/modules/controlcenter/dev/DevControlCenter.qml new file mode 100644 index 0000000..29592ca --- /dev/null +++ b/modules/controlcenter/dev/DevControlCenter.qml @@ -0,0 +1,94 @@ +pragma ComponentBehavior: Bound + +import "." +import ".." +import qs.components +import qs.components.controls +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property ShellScreen screen + readonly property int rounding: floating ? 0 : Appearance.rounding.normal + + property alias floating: session.floating + property alias active: session.active + property alias navExpanded: session.navExpanded + + readonly property DevSession session: DevSession { + id: session + + root: root + } + + function close(): void { + } + + implicitWidth: implicitHeight * Config.controlCenter.sizes.ratio + implicitHeight: screen.height * Config.controlCenter.sizes.heightMult + + GridLayout { + anchors.fill: parent + + rowSpacing: 0 + columnSpacing: 0 + rows: root.floating ? 2 : 1 + columns: 2 + + Loader { + Layout.fillWidth: true + Layout.columnSpan: 2 + + asynchronous: true + active: root.floating + visible: active + + sourceComponent: DevWindowTitle { + screen: root.screen + session: root.session + } + } + + StyledRect { + Layout.fillHeight: true + + topLeftRadius: root.rounding + bottomLeftRadius: root.rounding + implicitWidth: navRail.implicitWidth + color: Colours.tPalette.m3surfaceContainer + + CustomMouseArea { + anchors.fill: parent + + function onWheel(event: WheelEvent): void { + if (event.angleDelta.y < 0) + root.session.activeIndex = Math.min(root.session.activeIndex + 1, root.session.panes.length - 1); + else if (event.angleDelta.y > 0) + root.session.activeIndex = Math.max(root.session.activeIndex - 1, 0); + } + } + + DevNavRail { + id: navRail + + screen: root.screen + session: root.session + } + } + + DevPanes { + Layout.fillWidth: true + Layout.fillHeight: true + + topRightRadius: root.rounding + bottomRightRadius: root.rounding + session: root.session + } + } +} + diff --git a/modules/controlcenter/dev/DevDebugPane.qml b/modules/controlcenter/dev/DevDebugPane.qml new file mode 100644 index 0000000..88d6542 --- /dev/null +++ b/modules/controlcenter/dev/DevDebugPane.qml @@ -0,0 +1,170 @@ +pragma ComponentBehavior: Bound + +import "." +import ".." +import qs.components +import qs.components.controls +import qs.components.containers +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property DevSession session + + anchors.fill: parent + + ColumnLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Debug Panel") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + // Action Buttons Section + StyledRect { + Layout.fillWidth: true + implicitHeight: buttonsLayout.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: buttonsLayout + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Actions") + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + + Flow { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + TextButton { + text: qsTr("Clear Log") + onClicked: { + debugOutput.text = ""; + appendLog("Debug log cleared"); + } + } + + TextButton { + text: qsTr("Test Action") + onClicked: { + appendLog("Test action executed at " + new Date().toLocaleTimeString()); + } + } + + TextButton { + text: qsTr("Log Network State") + onClicked: { + appendLog("Network state:"); + appendLog(" Active: " + (root.session.network.active ? "Yes" : "No")); + } + } + } + } + } + + // Debug Output Section + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + + StyledText { + text: qsTr("Debug Output") + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + TextButton { + text: qsTr("Copy") + onClicked: { + debugOutput.selectAll(); + debugOutput.copy(); + debugOutput.deselect(); + appendLog("Output copied to clipboard"); + } + } + } + + StyledFlickable { + id: flickable + + Layout.fillWidth: true + Layout.fillHeight: true + flickableDirection: Flickable.VerticalFlick + contentHeight: debugOutput.implicitHeight + + TextEdit { + id: debugOutput + + width: flickable.width + readOnly: true + wrapMode: TextEdit.Wrap + font.family: Appearance.font.family.mono + font.pointSize: Appearance.font.size.smaller + renderType: TextEdit.NativeRendering + textFormat: TextEdit.PlainText + color: "#ffb0ca" // Use primary color - will be set programmatically + + Component.onCompleted: { + color = Colours.palette.m3primary; + appendLog("Debug panel initialized"); + } + + onTextChanged: { + // Ensure color stays set when text changes + color = Colours.palette.m3primary; + if (flickable.contentHeight > flickable.height) { + flickable.contentY = flickable.contentHeight - flickable.height; + } + } + } + } + + StyledScrollBar { + flickable: flickable + policy: ScrollBar.AlwaysOn + } + } + } + } + + function appendLog(message: string): void { + const timestamp = new Date().toLocaleTimeString(); + debugOutput.text += `[${timestamp}] ${message}\n`; + } + + function log(message: string): void { + appendLog(message); + } +} + diff --git a/modules/controlcenter/dev/DevNavRail.qml b/modules/controlcenter/dev/DevNavRail.qml new file mode 100644 index 0000000..d2f2d57 --- /dev/null +++ b/modules/controlcenter/dev/DevNavRail.qml @@ -0,0 +1,194 @@ +pragma ComponentBehavior: Bound + +import "." +import ".." +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property ShellScreen screen + required property DevSession session + + implicitWidth: layout.implicitWidth + Appearance.padding.larger * 4 + implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 + + ColumnLayout { + id: layout + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.larger * 2 + spacing: Appearance.spacing.normal + + states: State { + name: "expanded" + when: root.session.navExpanded + + PropertyChanges { + layout.spacing: Appearance.spacing.small + menuIcon.opacity: 0 + menuIconExpanded.opacity: 1 + menuIcon.rotation: 180 + menuIconExpanded.rotation: 0 + } + } + + transitions: Transition { + Anim { + properties: "spacing,opacity,rotation" + } + } + + Item { + id: menuBtn + + Layout.topMargin: Appearance.spacing.large + implicitWidth: menuIcon.implicitWidth + menuIcon.anchors.leftMargin * 2 + implicitHeight: menuIcon.implicitHeight + Appearance.padding.normal * 2 + + StateLayer { + radius: Appearance.rounding.small + + function onClicked(): void { + root.session.navExpanded = !root.session.navExpanded; + } + } + + MaterialIcon { + id: menuIcon + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.large + + text: "menu" + font.pointSize: Appearance.font.size.large + } + + MaterialIcon { + id: menuIconExpanded + + anchors.fill: menuIcon + text: "menu_open" + font.pointSize: menuIcon.font.pointSize + opacity: 0 + rotation: -180 + } + } + + NavItem { + Layout.topMargin: Appearance.spacing.large * 2 + icon: "wifi" + label: "wireless" + } + + NavItem { + icon: "bug_report" + label: "debug" + } + } + + component NavItem: Item { + id: item + + required property string icon + required property string label + readonly property bool active: root.session.active === label + + implicitWidth: background.implicitWidth + implicitHeight: background.implicitHeight + smallLabel.implicitHeight + smallLabel.anchors.topMargin + + states: State { + name: "expanded" + when: root.session.navExpanded + + PropertyChanges { + expandedLabel.opacity: 1 + smallLabel.opacity: 0 + background.implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2 + expandedLabel.anchors.leftMargin + expandedLabel.implicitWidth + background.implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 + item.implicitHeight: background.implicitHeight + } + } + + transitions: Transition { + Anim { + property: "opacity" + duration: Appearance.anim.durations.small + } + + Anim { + properties: "implicitWidth,implicitHeight" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + StyledRect { + id: background + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3secondaryContainer, item.active ? 1 : 0) + + implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2 + implicitHeight: icon.implicitHeight + Appearance.padding.small + + StateLayer { + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + + function onClicked(): void { + root.session.active = item.label; + } + } + + MaterialIcon { + id: icon + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.large + + text: item.icon + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.large + fill: item.active ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + StyledText { + id: expandedLabel + + anchors.left: icon.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.spacing.normal + + opacity: 0 + text: item.label + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.capitalization: Font.Capitalize + } + + StyledText { + id: smallLabel + + anchors.horizontalCenter: icon.horizontalCenter + anchors.top: icon.bottom + anchors.topMargin: Appearance.spacing.small / 2 + + text: item.label + font.pointSize: Appearance.font.size.small + font.capitalization: Font.Capitalize + } + } + } +} + diff --git a/modules/controlcenter/dev/DevPanes.qml b/modules/controlcenter/dev/DevPanes.qml new file mode 100644 index 0000000..6b5ce06 --- /dev/null +++ b/modules/controlcenter/dev/DevPanes.qml @@ -0,0 +1,70 @@ +pragma ComponentBehavior: Bound + +import "." +import ".." +import qs.components +import qs.services +import qs.config +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +ClippingRectangle { + id: root + + required property DevSession session + + color: "transparent" + + ColumnLayout { + id: layout + + spacing: 0 + y: -root.session.activeIndex * root.height + + Pane { + index: 0 + sourceComponent: DevWirelessPane { + session: root.session + } + } + + Pane { + index: 1 + sourceComponent: DevDebugPane { + session: root.session + } + } + + Behavior on y { + Anim {} + } + } + + component Pane: Item { + id: pane + + required property int index + property alias sourceComponent: loader.sourceComponent + + implicitWidth: root.width + implicitHeight: root.height + + Loader { + id: loader + + anchors.fill: parent + clip: true + asynchronous: true + active: { + if (root.session.activeIndex === pane.index) + return true; + + const ly = -layout.y; + const ty = pane.index * root.height; + return ly + root.height > ty && ly < ty + root.height; + } + } + } +} + diff --git a/modules/controlcenter/dev/DevSession.qml b/modules/controlcenter/dev/DevSession.qml new file mode 100644 index 0000000..d911386 --- /dev/null +++ b/modules/controlcenter/dev/DevSession.qml @@ -0,0 +1,23 @@ +import QtQuick + +QtObject { + readonly property list panes: ["wireless", "debug"] + + required property var root + property bool floating: false + property string active: panes[0] + property int activeIndex: 0 + property bool navExpanded: false + + component Network: QtObject { + property var active + property bool showPasswordDialog: false + property var pendingNetwork + } + + readonly property Network network: Network {} + + onActiveChanged: activeIndex = panes.indexOf(active) + onActiveIndexChanged: active = panes[activeIndex] +} + diff --git a/modules/controlcenter/dev/DevWindowFactory.qml b/modules/controlcenter/dev/DevWindowFactory.qml new file mode 100644 index 0000000..5682588 --- /dev/null +++ b/modules/controlcenter/dev/DevWindowFactory.qml @@ -0,0 +1,62 @@ +pragma Singleton + +import "." +import qs.components +import qs.services +import Quickshell +import QtQuick + +Singleton { + id: root + + function create(parent: Item, props: var): void { + devControlCenter.createObject(parent ?? dummy, props); + } + + QtObject { + id: dummy + } + + Component { + id: devControlCenter + + FloatingWindow { + id: win + + property alias active: cc.active + property alias navExpanded: cc.navExpanded + + color: Colours.tPalette.m3surface + + onVisibleChanged: { + if (!visible) + destroy(); + } + + minimumSize.width: 1000 + minimumSize.height: 600 + + implicitWidth: cc.implicitWidth + implicitHeight: cc.implicitHeight + + title: qsTr("Dev Panel - Wireless") + + DevControlCenter { + id: cc + + anchors.fill: parent + screen: win.screen + floating: true + + function close(): void { + win.destroy(); + } + } + + Behavior on color { + CAnim {} + } + } + } +} + diff --git a/modules/controlcenter/dev/DevWindowTitle.qml b/modules/controlcenter/dev/DevWindowTitle.qml new file mode 100644 index 0000000..9395532 --- /dev/null +++ b/modules/controlcenter/dev/DevWindowTitle.qml @@ -0,0 +1,53 @@ +import "." +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick + +StyledRect { + id: root + + required property ShellScreen screen + required property DevSession session + + implicitHeight: text.implicitHeight + Appearance.padding.normal + color: Colours.tPalette.m3surfaceContainer + + StyledText { + id: text + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + text: qsTr("Dev Panel - %1").arg(root.session.active.slice(0, 1).toUpperCase() + root.session.active.slice(1)) + font.capitalization: Font.Capitalize + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + Item { + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.normal + + implicitWidth: implicitHeight + implicitHeight: closeIcon.implicitHeight + Appearance.padding.small + + StateLayer { + radius: Appearance.rounding.full + + function onClicked(): void { + QsWindow.window.destroy(); + } + } + + MaterialIcon { + id: closeIcon + + anchors.centerIn: parent + text: "close" + } + } +} + diff --git a/modules/controlcenter/dev/DevWirelessPane.qml b/modules/controlcenter/dev/DevWirelessPane.qml new file mode 100644 index 0000000..feb0ce7 --- /dev/null +++ b/modules/controlcenter/dev/DevWirelessPane.qml @@ -0,0 +1,68 @@ +pragma ComponentBehavior: Bound + +import "." +import ".." +import qs.components +import qs.components.effects +import qs.components.containers +import qs.config +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + required property DevSession session + + anchors.fill: parent + + spacing: 0 + + Item { + Layout.preferredWidth: Math.floor(parent.width * 0.4) + Layout.minimumWidth: 420 + Layout.fillHeight: true + + // Blank placeholder for wireless list + Item { + anchors.fill: parent + anchors.margins: Appearance.padding.large + Appearance.padding.normal + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2 + } + + InnerBorder { + leftThickness: 0 + rightThickness: Appearance.padding.normal / 2 + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + ClippingRectangle { + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.leftMargin: 0 + anchors.rightMargin: Appearance.padding.normal / 2 + + radius: rightBorder.innerRadius + color: "transparent" + + // Blank placeholder for settings/details area + Item { + anchors.fill: parent + anchors.margins: Appearance.padding.large * 2 + } + } + + InnerBorder { + id: rightBorder + + leftThickness: Appearance.padding.normal / 2 + } + } +} + diff --git a/modules/utilities/cards/Toggles.qml b/modules/utilities/cards/Toggles.qml index 3d18e72..ccf1c7d 100644 --- a/modules/utilities/cards/Toggles.qml +++ b/modules/utilities/cards/Toggles.qml @@ -3,6 +3,7 @@ import qs.components.controls import qs.services import qs.config import qs.modules.controlcenter +import "../../controlcenter/dev" import Quickshell import Quickshell.Bluetooth import QtQuick @@ -92,6 +93,18 @@ StyledRect { visible: VPN.enabled onClicked: VPN.toggle() } + + Toggle { + icon: "bug_report" + inactiveOnColour: Colours.palette.m3onSurfaceVariant + toggle: false + onClicked: { + root.visibilities.utilities = false; + DevWindowFactory.create(null, { + screen: QsWindow.window?.screen ?? null + }); + } + } } } -- cgit v1.2.3-freya From f0ea26a71bb1359479c620ba3d571e129547c912 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Thu, 13 Nov 2025 20:52:09 -0500 Subject: controlcenter: removed dev panels --- modules/controlcenter/dev/DevControlCenter.qml | 94 -- modules/controlcenter/dev/DevDebugPane.qml | 1979 ------------------------ modules/controlcenter/dev/DevNavRail.qml | 194 --- modules/controlcenter/dev/DevPanes.qml | 70 - modules/controlcenter/dev/DevSession.qml | 23 - modules/controlcenter/dev/DevWindowFactory.qml | 62 - modules/controlcenter/dev/DevWindowTitle.qml | 53 - modules/controlcenter/dev/DevWirelessPane.qml | 68 - modules/utilities/cards/Toggles.qml | 12 - 9 files changed, 2555 deletions(-) delete mode 100644 modules/controlcenter/dev/DevControlCenter.qml delete mode 100644 modules/controlcenter/dev/DevDebugPane.qml delete mode 100644 modules/controlcenter/dev/DevNavRail.qml delete mode 100644 modules/controlcenter/dev/DevPanes.qml delete mode 100644 modules/controlcenter/dev/DevSession.qml delete mode 100644 modules/controlcenter/dev/DevWindowFactory.qml delete mode 100644 modules/controlcenter/dev/DevWindowTitle.qml delete mode 100644 modules/controlcenter/dev/DevWirelessPane.qml (limited to 'modules/utilities') diff --git a/modules/controlcenter/dev/DevControlCenter.qml b/modules/controlcenter/dev/DevControlCenter.qml deleted file mode 100644 index 29592ca..0000000 --- a/modules/controlcenter/dev/DevControlCenter.qml +++ /dev/null @@ -1,94 +0,0 @@ -pragma ComponentBehavior: Bound - -import "." -import ".." -import qs.components -import qs.components.controls -import qs.services -import qs.config -import Quickshell -import QtQuick -import QtQuick.Layouts - -Item { - id: root - - required property ShellScreen screen - readonly property int rounding: floating ? 0 : Appearance.rounding.normal - - property alias floating: session.floating - property alias active: session.active - property alias navExpanded: session.navExpanded - - readonly property DevSession session: DevSession { - id: session - - root: root - } - - function close(): void { - } - - implicitWidth: implicitHeight * Config.controlCenter.sizes.ratio - implicitHeight: screen.height * Config.controlCenter.sizes.heightMult - - GridLayout { - anchors.fill: parent - - rowSpacing: 0 - columnSpacing: 0 - rows: root.floating ? 2 : 1 - columns: 2 - - Loader { - Layout.fillWidth: true - Layout.columnSpan: 2 - - asynchronous: true - active: root.floating - visible: active - - sourceComponent: DevWindowTitle { - screen: root.screen - session: root.session - } - } - - StyledRect { - Layout.fillHeight: true - - topLeftRadius: root.rounding - bottomLeftRadius: root.rounding - implicitWidth: navRail.implicitWidth - color: Colours.tPalette.m3surfaceContainer - - CustomMouseArea { - anchors.fill: parent - - function onWheel(event: WheelEvent): void { - if (event.angleDelta.y < 0) - root.session.activeIndex = Math.min(root.session.activeIndex + 1, root.session.panes.length - 1); - else if (event.angleDelta.y > 0) - root.session.activeIndex = Math.max(root.session.activeIndex - 1, 0); - } - } - - DevNavRail { - id: navRail - - screen: root.screen - session: root.session - } - } - - DevPanes { - Layout.fillWidth: true - Layout.fillHeight: true - - topRightRadius: root.rounding - bottomRightRadius: root.rounding - session: root.session - } - } -} - diff --git a/modules/controlcenter/dev/DevDebugPane.qml b/modules/controlcenter/dev/DevDebugPane.qml deleted file mode 100644 index 1150f35..0000000 --- a/modules/controlcenter/dev/DevDebugPane.qml +++ /dev/null @@ -1,1979 +0,0 @@ -pragma ComponentBehavior: Bound - -import "." -import ".." -import qs.components -import qs.components.controls -import qs.components.containers -import qs.components.effects -import qs.config -import qs.services -import Quickshell -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts - -Item { - id: root - - required property DevSession session - - anchors.fill: parent - - // Track last failed connection - property string lastFailedSsid: "" - - // Connect to connection failure signal - Connections { - target: Nmcli - function onConnectionFailed(ssid: string) { - root.lastFailedSsid = ssid; - appendLog("Connection failed signal received for: " + ssid); - } - } - - StyledFlickable { - id: flickable - - anchors.fill: parent - anchors.margins: Appearance.padding.large - flickableDirection: Flickable.VerticalFlick - contentWidth: width - contentHeight: contentLayout.implicitHeight - - StyledScrollBar.vertical: StyledScrollBar { - flickable: flickable - } - - ColumnLayout { - id: contentLayout - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Debug Panel") - font.pointSize: Appearance.font.size.larger - font.weight: 500 - } - - // Action Buttons Section - StyledRect { - Layout.fillWidth: true - implicitHeight: buttonsLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: buttonsLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Actions") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - Flow { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - TextButton { - text: qsTr("Clear Log") - onClicked: { - debugOutput.text = ""; - appendLog("Debug log cleared"); - } - } - - TextButton { - text: qsTr("Test Action") - onClicked: { - appendLog("Test action executed at " + new Date().toLocaleTimeString()); - } - } - - TextButton { - text: qsTr("Log Network State") - onClicked: { - appendLog("Network state:"); - appendLog(" Active: " + (root.session.network.active ? "Yes" : "No")); - } - } - - TextButton { - text: qsTr("Get Device Status") - onClicked: { - appendLog("Getting device status..."); - try { - Nmcli.getDeviceStatus((output) => { - if (!output) { - appendLog(" Error: No output received"); - return; - } - appendLog("Device Status:"); - const lines = output.trim().split("\n"); - if (lines.length === 0 || (lines.length === 1 && lines[0].length === 0)) { - appendLog(" No devices found"); - } else { - for (const line of lines) { - if (line.length > 0) { - appendLog(" " + line); - } - } - } - }); - } catch (e) { - appendLog("Error: " + e); - } - } - } - - TextButton { - text: qsTr("Get Wireless Interfaces") - onClicked: { - appendLog("Getting wireless interfaces..."); - Nmcli.getWirelessInterfaces((interfaces) => { - appendLog("Wireless Interfaces: " + interfaces.length); - for (const iface of interfaces) { - appendLog(` ${iface.device}: ${iface.state} (${iface.connection})`); - } - }); - } - } - - TextButton { - text: qsTr("Get Ethernet Interfaces") - onClicked: { - appendLog("Getting ethernet interfaces..."); - Nmcli.getEthernetInterfaces((interfaces) => { - appendLog("Ethernet Interfaces: " + interfaces.length); - for (const iface of interfaces) { - appendLog(` ${iface.device}: ${iface.state} (${iface.connection})`); - } - }); - } - } - - TextButton { - text: qsTr("Refresh Status") - onClicked: { - appendLog("Refreshing connection status..."); - Nmcli.refreshStatus((status) => { - appendLog("Connection Status:"); - appendLog(" Connected: " + (status.connected ? "Yes" : "No")); - appendLog(" Interface: " + (status.interface || "None")); - appendLog(" Connection: " + (status.connection || "None")); - }); - } - } - - TextButton { - text: qsTr("Check Interface") - onClicked: { - appendLog("Checking interface connection status..."); - // Check first wireless interface if available - if (Nmcli.wirelessInterfaces.length > 0) { - const iface = Nmcli.wirelessInterfaces[0].device; - appendLog("Checking: " + iface); - Nmcli.isInterfaceConnected(iface, (connected) => { - appendLog(` ${iface}: ${connected ? "Connected" : "Disconnected"}`); - }); - } else { - appendLog("No wireless interfaces found"); - } - } - } - } - } - } - - // WiFi Radio Control Section - StyledRect { - Layout.fillWidth: true - implicitHeight: wifiRadioLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: wifiRadioLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("WiFi Radio Control") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Status: ") + (Nmcli.wifiEnabled ? qsTr("Enabled") : qsTr("Disabled")) - color: Nmcli.wifiEnabled ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Toggle WiFi") - onClicked: { - appendLog("Toggling WiFi radio..."); - Nmcli.toggleWifi((result) => { - if (result.success) { - appendLog("WiFi radio toggled: " + (Nmcli.wifiEnabled ? "Enabled" : "Disabled")); - } else { - appendLog("Failed to toggle WiFi: " + (result.error || "Unknown error")); - } - }); - } - } - - TextButton { - text: qsTr("Enable") - onClicked: { - appendLog("Enabling WiFi radio..."); - Nmcli.enableWifi(true, (result) => { - if (result.success) { - appendLog("WiFi radio enabled"); - } else { - appendLog("Failed to enable WiFi: " + (result.error || "Unknown error")); - } - }); - } - } - - TextButton { - text: qsTr("Disable") - onClicked: { - appendLog("Disabling WiFi radio..."); - Nmcli.enableWifi(false, (result) => { - if (result.success) { - appendLog("WiFi radio disabled"); - } else { - appendLog("Failed to disable WiFi: " + (result.error || "Unknown error")); - } - }); - } - } - - TextButton { - text: qsTr("Check Status") - onClicked: { - appendLog("Checking WiFi radio status..."); - Nmcli.getWifiStatus((enabled) => { - appendLog("WiFi radio status: " + (enabled ? "Enabled" : "Disabled")); - }); - } - } - } - } - } - - // Network List Management Section - StyledRect { - Layout.fillWidth: true - implicitHeight: networkListLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: networkListLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Network List Management") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Networks: %1").arg(Nmcli.networks.length) - } - - StyledText { - visible: Nmcli.active - text: qsTr("Active: %1").arg(Nmcli.active.ssid) - color: Colours.palette.m3primary - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Refresh Networks") - onClicked: { - appendLog("Refreshing network list..."); - Nmcli.getNetworks((networks) => { - appendLog("Found " + networks.length + " networks"); - if (Nmcli.active) { - appendLog("Active network: " + Nmcli.active.ssid + " (Signal: " + Nmcli.active.strength + "%, Security: " + (Nmcli.active.isSecure ? Nmcli.active.security : "Open") + ")"); - } else { - appendLog("No active network"); - } - }); - } - } - - TextButton { - text: qsTr("List All Networks") - onClicked: { - appendLog("Network list:"); - if (Nmcli.networks.length === 0) { - appendLog(" No networks found"); - } else { - for (let i = 0; i < Nmcli.networks.length; i++) { - const net = Nmcli.networks[i]; - const activeMark = net.active ? " [ACTIVE]" : ""; - appendLog(` ${i + 1}. ${net.ssid}${activeMark}`); - appendLog(` Signal: ${net.strength}%, Freq: ${net.frequency}MHz, Security: ${net.isSecure ? net.security : "Open"}`); - if (net.bssid) { - appendLog(` BSSID: ${net.bssid}`); - } - } - } - } - } - } - } - } - - // Interface Selector Section (for future features) - Item { - Layout.fillWidth: true - implicitHeight: interfaceSelectorContainer.implicitHeight - z: 10 // Ensure dropdown menu appears above other elements - - StyledRect { - id: interfaceSelectorContainer - - anchors.fill: parent - implicitHeight: interfaceSelectorLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: interfaceSelectorLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Interface Selector") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - SplitButton { - id: interfaceSelector - - type: SplitButton.Tonal - fallbackText: qsTr("Select Interface") - fallbackIcon: "settings_ethernet" - menuItems: interfaceList.instances - menuOnTop: true // Position menu above button to avoid being covered - - property string selectedInterface: "" - - menu.onItemSelected: (item) => { - interfaceSelector.selectedInterface = item.modelData.device; - appendLog("Selected interface: " + item.modelData.device + " (" + item.modelData.type + ")"); - } - - Variants { - id: interfaceList - - model: interfaceSelector.interfaces - - MenuItem { - required property var modelData - - text: modelData.device + " (" + modelData.type + ")" - icon: modelData.type === "wifi" ? "wifi" : "settings_ethernet" - } - } - - property list interfaces: [] - - function refreshInterfaces(): void { - appendLog("Refreshing interface list..."); - Nmcli.getAllInterfaces((interfaces) => { - interfaceSelector.interfaces = interfaces; - if (interfaces.length > 0) { - // Wait for Variants to create instances, then set active - Qt.callLater(() => { - if (interfaceList.instances.length > 0) { - interfaceSelector.active = interfaceList.instances[0]; - interfaceSelector.selectedInterface = interfaces[0].device; - } - }); - appendLog("Found " + interfaces.length + " interfaces"); - } else { - interfaceSelector.selectedInterface = ""; - appendLog("No interfaces found"); - } - }); - } - - Component.onCompleted: { - // Ensure menu appears above other elements - menu.z = 100; - } - } - - TextButton { - text: qsTr("Refresh") - onClicked: { - interfaceSelector.refreshInterfaces(); - } - } - - TextButton { - text: qsTr("Up") - enabled: interfaceSelector.selectedInterface.length > 0 - onClicked: { - if (interfaceSelector.selectedInterface) { - appendLog("Bringing interface up: " + interfaceSelector.selectedInterface); - Nmcli.bringInterfaceUp(interfaceSelector.selectedInterface, (result) => { - if (result.success) { - appendLog("Interface up: Success"); - } else { - appendLog("Interface up: Failed (exit code: " + result.exitCode + ")"); - if (result.error && result.error.length > 0) { - appendLog("Error: " + result.error); - } - } - // Refresh interface list after bringing up - Qt.callLater(() => { - interfaceSelector.refreshInterfaces(); - }, 500); - }); - } - } - } - - TextButton { - text: qsTr("Down") - enabled: interfaceSelector.selectedInterface.length > 0 - onClicked: { - if (interfaceSelector.selectedInterface) { - appendLog("Bringing interface down: " + interfaceSelector.selectedInterface); - Nmcli.bringInterfaceDown(interfaceSelector.selectedInterface, (result) => { - if (result.success) { - appendLog("Interface down: Success"); - } else { - appendLog("Interface down: Failed (exit code: " + result.exitCode + ")"); - if (result.error && result.error.length > 0) { - appendLog("Error: " + result.error); - } - } - // Refresh interface list after bringing down - Qt.callLater(() => { - interfaceSelector.refreshInterfaces(); - }, 500); - }); - } - } - } - } - } - } - } - - // Wireless SSID Selector Section - Item { - Layout.fillWidth: true - implicitHeight: ssidSelectorContainer.implicitHeight - z: 10 // Ensure dropdown menu appears above other elements - - StyledRect { - id: ssidSelectorContainer - - anchors.fill: parent - implicitHeight: ssidSelectorLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: ssidSelectorLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Wireless SSID Selector") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - SplitButton { - id: ssidSelector - - type: SplitButton.Tonal - fallbackText: qsTr("Select SSID") - fallbackIcon: "wifi" - menuItems: ssidList.instances - menuOnTop: true - - property string selectedSSID: "" - - menu.onItemSelected: (item) => { - ssidSelector.selectedSSID = item.modelData.ssid; - appendLog("Selected SSID: " + item.modelData.ssid + " (Signal: " + item.modelData.signal + ", Security: " + item.modelData.security + ")"); - } - - Component.onCompleted: { - // Ensure menu appears above other elements - menu.z = 100; - } - - Variants { - id: ssidList - - model: ssidSelector.ssids - - MenuItem { - required property var modelData - - text: modelData.ssid + (modelData.signal ? " (" + modelData.signal + "%)" : "") - icon: "wifi" - } - } - - property list ssids: [] - - function scanForSSIDs(): void { - appendLog("Scanning for wireless networks..."); - // Use first wireless interface if available, or let nmcli choose - let iface = ""; - if (interfaceSelector.selectedInterface) { - // Check if selected interface is wireless - for (const i of interfaceSelector.interfaces) { - if (i.device === interfaceSelector.selectedInterface && i.type === "wifi") { - iface = interfaceSelector.selectedInterface; - break; - } - } - } - - // If no wireless interface selected, use first available - if (!iface && Nmcli.wirelessInterfaces.length > 0) { - iface = Nmcli.wirelessInterfaces[0].device; - } - - Nmcli.scanWirelessNetworks(iface, (scanResult) => { - if (scanResult.success) { - appendLog("Scan completed, fetching SSID list..."); - // Wait a moment for scan results to be available - Qt.callLater(() => { - Nmcli.getWirelessSSIDs(iface, (ssids) => { - ssidSelector.ssids = ssids; - if (ssids.length > 0) { - Qt.callLater(() => { - if (ssidList.instances.length > 0) { - ssidSelector.active = ssidList.instances[0]; - ssidSelector.selectedSSID = ssids[0].ssid; - } - }); - appendLog("Found " + ssids.length + " SSIDs"); - } else { - appendLog("No SSIDs found"); - } - }); - }, 1000); - } else { - appendLog("Scan failed: " + (scanResult.error || "Unknown error")); - } - }); - } - } - - TextButton { - text: qsTr("Scan") - onClicked: { - ssidSelector.scanForSSIDs(); - } - } - } - } - } - } - - // Wireless Connection Test Section - StyledRect { - Layout.fillWidth: true - implicitHeight: connectionTestLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: connectionTestLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Wireless Connection Test") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("SSID: %1").arg(ssidSelector.selectedSSID || "None selected") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Connect (No Password)") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - appendLog("Connecting to: " + ssidSelector.selectedSSID + " (no password)"); - // Find the network to get BSSID - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - const bssid = network ? network.bssid : ""; - Nmcli.connectWireless(ssidSelector.selectedSSID, "", bssid, (result) => { - if (result.success) { - appendLog("Connection succeeded!"); - // Refresh network list after connection - Qt.callLater(() => { - Nmcli.getNetworks(() => {}); - }, 1000); - } else { - appendLog("Connection failed: " + (result.error || "Unknown error")); - // Refresh network list anyway to check status - Qt.callLater(() => { - Nmcli.getNetworks(() => {}); - }, 1000); - } - }); - appendLog("Connection initiated, tracking pending connection..."); - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Password:") - } - - Item { - Layout.fillWidth: true - implicitHeight: passwordField.implicitHeight + Appearance.padding.small * 2 - - StyledRect { - anchors.fill: parent - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - border.width: passwordField.activeFocus ? 2 : 1 - border.color: passwordField.activeFocus ? Colours.palette.m3primary : Colours.palette.m3outline - - Behavior on border.color { - CAnim {} - } - } - - StyledTextField { - id: passwordField - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal - - echoMode: TextField.Password - placeholderText: qsTr("Enter password") - - Keys.onReturnPressed: { - if (connectWithPasswordButton.enabled) { - connectWithPasswordButton.clicked(); - } - } - Keys.onEnterPressed: { - if (connectWithPasswordButton.enabled) { - connectWithPasswordButton.clicked(); - } - } - } - } - - TextButton { - id: connectWithPasswordButton - text: qsTr("Connect") - enabled: ssidSelector.selectedSSID.length > 0 && passwordField.text.length > 0 - onClicked: { - if (ssidSelector.selectedSSID && passwordField.text) { - appendLog("Connecting to: " + ssidSelector.selectedSSID + " (with password)"); - // Find the network to get BSSID - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - const bssid = network ? network.bssid : ""; - Nmcli.connectWireless(ssidSelector.selectedSSID, passwordField.text, bssid, (result) => { - if (result.success) { - appendLog("Connection succeeded!"); - // Clear password field - passwordField.text = ""; - // Refresh network list after connection - Qt.callLater(() => { - Nmcli.getNetworks(() => {}); - }, 1000); - } else { - appendLog("Connection failed: " + (result.error || "Unknown error")); - if (result.exitCode !== 0) { - appendLog("Exit code: " + result.exitCode); - } - // Refresh network list anyway to check status - Qt.callLater(() => { - Nmcli.getNetworks(() => {}); - }, 1000); - } - }); - appendLog("Connection initiated, tracking pending connection..."); - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: { - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - const bssid = network && network.bssid ? network.bssid : "N/A"; - return qsTr("BSSID: %1").arg(bssid); - } - } - - Item { - Layout.fillWidth: true - } - } - } - } - - // Saved Connection Profiles Section - StyledRect { - Layout.fillWidth: true - implicitHeight: savedProfilesLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: savedProfilesLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Saved Connection Profiles") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Connections: %1").arg(Nmcli.savedConnections.length) - } - - StyledText { - text: qsTr("WiFi SSIDs: %1").arg(Nmcli.savedConnectionSsids.length) - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Refresh") - onClicked: { - appendLog("Refreshing saved connections..."); - Nmcli.loadSavedConnections((ssids) => { - appendLog("Found " + Nmcli.savedConnections.length + " saved connections"); - appendLog("Found " + Nmcli.savedConnectionSsids.length + " WiFi SSIDs"); - }); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Selected SSID: %1").arg(ssidSelector.selectedSSID || "None") - } - - StyledText { - visible: ssidSelector.selectedSSID.length > 0 - text: { - if (!ssidSelector.selectedSSID) return ""; - const hasProfile = Nmcli.hasSavedProfile(ssidSelector.selectedSSID); - return hasProfile ? qsTr("[Saved Profile]") : qsTr("[Not Saved]"); - } - color: { - if (!ssidSelector.selectedSSID) return Colours.palette.m3onSurface; - const hasProfile = Nmcli.hasSavedProfile(ssidSelector.selectedSSID); - return hasProfile ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant; - } - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Check Profile") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - const hasProfile = Nmcli.hasSavedProfile(ssidSelector.selectedSSID); - appendLog("Profile check for '" + ssidSelector.selectedSSID + "': " + (hasProfile ? "Saved" : "Not saved")); - } - } - } - - TextButton { - text: qsTr("Forget Network") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - appendLog("Forgetting network: " + ssidSelector.selectedSSID); - Nmcli.forgetNetwork(ssidSelector.selectedSSID, (result) => { - if (result.success) { - appendLog("Network forgotten successfully"); - } else { - appendLog("Failed to forget network: " + (result.error || "Unknown error")); - } - }); - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - TextButton { - text: qsTr("List All Saved SSIDs") - onClicked: { - appendLog("Saved WiFi SSIDs:"); - if (Nmcli.savedConnectionSsids.length === 0) { - appendLog(" No saved SSIDs"); - } else { - for (let i = 0; i < Nmcli.savedConnectionSsids.length; i++) { - appendLog(" " + (i + 1) + ". " + Nmcli.savedConnectionSsids[i]); - } - } - } - } - - TextButton { - text: qsTr("List All Connections") - onClicked: { - appendLog("Saved Connections:"); - if (Nmcli.savedConnections.length === 0) { - appendLog(" No saved connections"); - } else { - for (let i = 0; i < Nmcli.savedConnections.length; i++) { - appendLog(" " + (i + 1) + ". " + Nmcli.savedConnections[i]); - } - } - } - } - } - } - } - - // Pending Connection Tracking Section - StyledRect { - Layout.fillWidth: true - implicitHeight: pendingConnectionLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: pendingConnectionLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Pending Connection Tracking") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Status: %1").arg(Nmcli.pendingConnection ? "Connecting..." : "No pending connection") - color: Nmcli.pendingConnection ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant - } - - StyledText { - visible: Nmcli.pendingConnection - text: qsTr("SSID: %1").arg(Nmcli.pendingConnection ? Nmcli.pendingConnection.ssid : "") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Check Status") - onClicked: { - if (Nmcli.pendingConnection) { - appendLog("Pending connection: " + Nmcli.pendingConnection.ssid); - appendLog("BSSID: " + (Nmcli.pendingConnection.bssid || "N/A")); - const connected = Nmcli.active && Nmcli.active.ssid === Nmcli.pendingConnection.ssid; - appendLog("Connected: " + (connected ? "Yes" : "No")); - if (connected) { - appendLog("Connection succeeded!"); - } else { - appendLog("Still connecting..."); - } - } else { - appendLog("No pending connection"); - } - } - } - - TextButton { - text: qsTr("Clear Pending") - enabled: Nmcli.pendingConnection !== null - onClicked: { - if (Nmcli.pendingConnection) { - appendLog("Clearing pending connection: " + Nmcli.pendingConnection.ssid); - Nmcli.pendingConnection = null; - appendLog("Pending connection cleared"); - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Active Network: %1").arg(Nmcli.active ? Nmcli.active.ssid : "None") - color: Nmcli.active ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Refresh Networks & Check") - onClicked: { - appendLog("Refreshing network list to check pending connection..."); - Nmcli.getNetworks((networks) => { - appendLog("Network list refreshed"); - if (Nmcli.pendingConnection) { - const connected = Nmcli.active && Nmcli.active.ssid === Nmcli.pendingConnection.ssid; - appendLog("Pending connection check: " + (connected ? "Connected!" : "Still connecting...")); - } - }); - } - } - } - } - } - - // Connection Failure Handling Section - StyledRect { - Layout.fillWidth: true - implicitHeight: connectionFailureLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: connectionFailureLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Connection Failure Handling") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Last Failed SSID: %1").arg(lastFailedSsid || "None") - color: lastFailedSsid ? Colours.palette.m3error : Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Clear Failure") - enabled: lastFailedSsid.length > 0 - onClicked: { - lastFailedSsid = ""; - appendLog("Cleared failure status"); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Test Password Detection") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Test Secure Network (No Password)") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - if (network && network.isSecure) { - appendLog("Testing connection to secure network without password (should detect password requirement)"); - const bssid = network ? network.bssid : ""; - Nmcli.connectWireless(ssidSelector.selectedSSID, "", bssid, (result) => { - if (result.needsPassword) { - appendLog("✓ Password requirement detected correctly!"); - appendLog("Error: " + (result.error || "N/A")); - } else if (result.success) { - appendLog("Connection succeeded (saved password used)"); - } else { - appendLog("Connection failed: " + (result.error || "Unknown error")); - } - }); - } else { - appendLog("Selected network is not secure, cannot test password detection"); - } - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Connection Retry Test") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Test Retry Logic") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - appendLog("Testing connection retry logic (will retry up to 2 times on failure)"); - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - const bssid = network ? network.bssid : ""; - // Use invalid password to trigger failure - Nmcli.connectWireless(ssidSelector.selectedSSID, "invalid_password_test", bssid, (result) => { - if (result.success) { - appendLog("Connection succeeded (unexpected)"); - } else { - appendLog("Connection failed after retries: " + (result.error || "Unknown error")); - } - }); - } - } - } - } - } - } - - // Password Callback Handling Section - StyledRect { - Layout.fillWidth: true - implicitHeight: passwordCallbackLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: passwordCallbackLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Password Callback Handling") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Selected SSID: %1").arg(ssidSelector.selectedSSID || "None") - } - - StyledText { - visible: ssidSelector.selectedSSID.length > 0 - text: { - if (!ssidSelector.selectedSSID) return ""; - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - if (!network) return ""; - return network.isSecure ? qsTr("[Secure]") : qsTr("[Open]"); - } - color: { - if (!ssidSelector.selectedSSID) return Colours.palette.m3onSurface; - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - if (!network) return Colours.palette.m3onSurface; - return network.isSecure ? Colours.palette.m3error : Colours.palette.m3primary; - } - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Test Password Check (Secure)") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - if (network && network.isSecure) { - appendLog("Testing password check for secure network: " + ssidSelector.selectedSSID); - appendLog("This will try saved password first, then prompt if needed"); - const bssid = network ? network.bssid : ""; - Nmcli.connectToNetworkWithPasswordCheck(ssidSelector.selectedSSID, true, (result) => { - if (result.success) { - if (result.usedSavedPassword) { - appendLog("✓ Connection succeeded using saved password!"); - } else { - appendLog("✓ Connection succeeded!"); - } - // Refresh network list - Qt.callLater(() => { - Nmcli.getNetworks(() => {}); - }, 1000); - } else if (result.needsPassword) { - appendLog("→ Password required - callback triggered"); - appendLog(" Error: " + (result.error || "N/A")); - appendLog(" (In real UI, this would show password dialog)"); - } else { - appendLog("✗ Connection failed: " + (result.error || "Unknown error")); - } - }, bssid); - } else { - appendLog("Selected network is not secure, cannot test password check"); - } - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Test Open Network") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Test Password Check (Open)") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - if (network && !network.isSecure) { - appendLog("Testing password check for open network: " + ssidSelector.selectedSSID); - appendLog("Open networks should connect directly without password"); - const bssid = network ? network.bssid : ""; - Nmcli.connectToNetworkWithPasswordCheck(ssidSelector.selectedSSID, false, (result) => { - if (result.success) { - appendLog("✓ Connection succeeded!"); - // Refresh network list - Qt.callLater(() => { - Nmcli.getNetworks(() => {}); - }, 1000); - } else { - appendLog("✗ Connection failed: " + (result.error || "Unknown error")); - } - }, bssid); - } else { - appendLog("Selected network is not open, cannot test open network handling"); - } - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Test with Saved Password") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Test Secure Network (Has Saved Password)") - enabled: ssidSelector.selectedSSID.length > 0 - onClicked: { - if (ssidSelector.selectedSSID) { - const network = Nmcli.networks.find(n => n.ssid === ssidSelector.selectedSSID); - if (network && network.isSecure) { - const hasSaved = Nmcli.hasSavedProfile(ssidSelector.selectedSSID); - appendLog("Testing password check for: " + ssidSelector.selectedSSID); - appendLog("Has saved profile: " + (hasSaved ? "Yes" : "No")); - if (hasSaved) { - appendLog("This should connect using saved password without prompting"); - } else { - appendLog("This should prompt for password since no saved profile exists"); - } - const bssid = network ? network.bssid : ""; - Nmcli.connectToNetworkWithPasswordCheck(ssidSelector.selectedSSID, true, (result) => { - if (result.success) { - if (result.usedSavedPassword) { - appendLog("✓ Connection succeeded using saved password!"); - } else { - appendLog("✓ Connection succeeded!"); - } - // Refresh network list - Qt.callLater(() => { - Nmcli.getNetworks(() => {}); - }, 1000); - } else if (result.needsPassword) { - appendLog("→ Password required - callback triggered"); - appendLog(" (In real UI, this would show password dialog)"); - } else { - appendLog("✗ Connection failed: " + (result.error || "Unknown error")); - } - }, bssid); - } else { - appendLog("Selected network is not secure, cannot test saved password"); - } - } - } - } - } - } - } - - // Device Details Parsing Section - StyledRect { - Layout.fillWidth: true - implicitHeight: deviceDetailsLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: deviceDetailsLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Device Details Parsing") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Wireless Device Details") - font.weight: 500 - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Get Wireless Details") - onClicked: { - const activeInterface = interfaceSelector.selectedInterface; - if (activeInterface && activeInterface.length > 0) { - appendLog("Getting wireless device details for: " + activeInterface); - Nmcli.getWirelessDeviceDetails(activeInterface, (details) => { - if (details) { - appendLog("Wireless Device Details:"); - appendLog(" IP Address: " + (details.ipAddress || "N/A")); - appendLog(" Gateway: " + (details.gateway || "N/A")); - appendLog(" Subnet: " + (details.subnet || "N/A")); - appendLog(" MAC Address: " + (details.macAddress || "N/A")); - appendLog(" DNS: " + (details.dns && details.dns.length > 0 ? details.dns.join(", ") : "N/A")); - } else { - appendLog("Failed to get wireless device details"); - } - }); - } else { - appendLog("Getting wireless device details for active interface"); - Nmcli.getWirelessDeviceDetails("", (details) => { - if (details) { - appendLog("Wireless Device Details:"); - appendLog(" IP Address: " + (details.ipAddress || "N/A")); - appendLog(" Gateway: " + (details.gateway || "N/A")); - appendLog(" Subnet: " + (details.subnet || "N/A")); - appendLog(" MAC Address: " + (details.macAddress || "N/A")); - appendLog(" DNS: " + (details.dns && details.dns.length > 0 ? details.dns.join(", ") : "N/A")); - } else { - appendLog("No active wireless interface or failed to get details"); - } - }); - } - } - } - - TextButton { - text: qsTr("Show Current") - onClicked: { - if (Nmcli.wirelessDeviceDetails) { - const details = Nmcli.wirelessDeviceDetails; - appendLog("Current Wireless Device Details:"); - appendLog(" IP Address: " + (details.ipAddress || "N/A")); - appendLog(" Gateway: " + (details.gateway || "N/A")); - appendLog(" Subnet: " + (details.subnet || "N/A")); - appendLog(" MAC Address: " + (details.macAddress || "N/A")); - appendLog(" DNS: " + (details.dns && details.dns.length > 0 ? details.dns.join(", ") : "N/A")); - } else { - appendLog("No wireless device details available"); - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Ethernet Device Details") - font.weight: 500 - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Get Ethernet Details") - onClicked: { - const activeInterface = interfaceSelector.selectedInterface; - if (activeInterface && activeInterface.length > 0) { - appendLog("Getting ethernet device details for: " + activeInterface); - Nmcli.getEthernetDeviceDetails(activeInterface, (details) => { - if (details) { - appendLog("Ethernet Device Details:"); - appendLog(" IP Address: " + (details.ipAddress || "N/A")); - appendLog(" Gateway: " + (details.gateway || "N/A")); - appendLog(" Subnet: " + (details.subnet || "N/A")); - appendLog(" MAC Address: " + (details.macAddress || "N/A")); - appendLog(" Speed: " + (details.speed || "N/A")); - appendLog(" DNS: " + (details.dns && details.dns.length > 0 ? details.dns.join(", ") : "N/A")); - } else { - appendLog("Failed to get ethernet device details"); - } - }); - } else { - appendLog("Getting ethernet device details for active interface"); - Nmcli.getEthernetDeviceDetails("", (details) => { - if (details) { - appendLog("Ethernet Device Details:"); - appendLog(" IP Address: " + (details.ipAddress || "N/A")); - appendLog(" Gateway: " + (details.gateway || "N/A")); - appendLog(" Subnet: " + (details.subnet || "N/A")); - appendLog(" MAC Address: " + (details.macAddress || "N/A")); - appendLog(" Speed: " + (details.speed || "N/A")); - appendLog(" DNS: " + (details.dns && details.dns.length > 0 ? details.dns.join(", ") : "N/A")); - } else { - appendLog("No active ethernet interface or failed to get details"); - } - }); - } - } - } - - TextButton { - text: qsTr("Show Current") - onClicked: { - if (Nmcli.ethernetDeviceDetails) { - const details = Nmcli.ethernetDeviceDetails; - appendLog("Current Ethernet Device Details:"); - appendLog(" IP Address: " + (details.ipAddress || "N/A")); - appendLog(" Gateway: " + (details.gateway || "N/A")); - appendLog(" Subnet: " + (details.subnet || "N/A")); - appendLog(" MAC Address: " + (details.macAddress || "N/A")); - appendLog(" Speed: " + (details.speed || "N/A")); - appendLog(" DNS: " + (details.dns && details.dns.length > 0 ? details.dns.join(", ") : "N/A")); - } else { - appendLog("No ethernet device details available"); - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("CIDR to Subnet Mask Test") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Test CIDR Conversion") - onClicked: { - appendLog("Testing CIDR to Subnet Mask conversion:"); - const testCases = ["8", "16", "24", "32", "0", "25", "30"]; - for (let i = 0; i < testCases.length; i++) { - const cidr = testCases[i]; - const subnet = Nmcli.cidrToSubnetMask(cidr); - appendLog(" /" + cidr + " -> " + (subnet || "Invalid")); - } - } - } - } - } - } - - // Connection Status Monitoring Section - StyledRect { - Layout.fillWidth: true - implicitHeight: connectionMonitoringLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: connectionMonitoringLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Connection Status Monitoring") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Active Network: %1").arg(Nmcli.active ? Nmcli.active.ssid : "None") - color: Nmcli.active ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant - } - - StyledText { - visible: Nmcli.active - text: Nmcli.active ? qsTr("Signal: %1%").arg(Nmcli.active.strength) : "" - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Refresh Networks") - onClicked: { - appendLog("Manually refreshing network list..."); - Nmcli.getNetworks((networks) => { - appendLog("Network list refreshed: " + networks.length + " networks"); - if (Nmcli.active) { - appendLog("Active network: " + Nmcli.active.ssid); - } else { - appendLog("No active network"); - } - }); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Monitor Status") - } - - StyledText { - text: qsTr("Monitoring connection changes (automatic refresh enabled)") - color: Colours.palette.m3primary - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Test Connection Change") - onClicked: { - appendLog("Testing connection change detection..."); - appendLog("This will trigger a manual refresh to simulate a connection change"); - Nmcli.refreshOnConnectionChange(); - appendLog("Refresh triggered - check if network list and device details updated"); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Device Details Auto-Refresh") - } - - StyledText { - text: { - if (Nmcli.wirelessDeviceDetails) { - return qsTr("Wireless: %1").arg(Nmcli.wirelessDeviceDetails.ipAddress || "N/A"); - } else if (Nmcli.ethernetDeviceDetails) { - return qsTr("Ethernet: %1").arg(Nmcli.ethernetDeviceDetails.ipAddress || "N/A"); - } else { - return qsTr("No device details"); - } - } - color: (Nmcli.wirelessDeviceDetails || Nmcli.ethernetDeviceDetails) ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Refresh Device Details") - onClicked: { - appendLog("Manually refreshing device details..."); - if (Nmcli.active && Nmcli.active.active) { - appendLog("Active network detected, refreshing device details..."); - // Refresh wireless device details - if (Nmcli.wirelessInterfaces.length > 0) { - const activeWireless = Nmcli.wirelessInterfaces.find(iface => { - return iface.state === "connected" || iface.state.startsWith("connected"); - }); - if (activeWireless && activeWireless.device) { - Nmcli.getWirelessDeviceDetails(activeWireless.device, (details) => { - if (details) { - appendLog("Wireless device details refreshed"); - } - }); - } - } - // Refresh ethernet device details - if (Nmcli.ethernetInterfaces.length > 0) { - const activeEthernet = Nmcli.ethernetInterfaces.find(iface => { - return iface.state === "connected" || iface.state.startsWith("connected"); - }); - if (activeEthernet && activeEthernet.device) { - Nmcli.getEthernetDeviceDetails(activeEthernet.device, (details) => { - if (details) { - appendLog("Ethernet device details refreshed"); - } - }); - } - } - } else { - appendLog("No active network, clearing device details"); - Nmcli.wirelessDeviceDetails = null; - Nmcli.ethernetDeviceDetails = null; - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Connection Events") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Show Active Network Info") - onClicked: { - if (Nmcli.active) { - appendLog("Active Network Information:"); - appendLog(" SSID: " + Nmcli.active.ssid); - appendLog(" BSSID: " + (Nmcli.active.bssid || "N/A")); - appendLog(" Signal: " + Nmcli.active.strength + "%"); - appendLog(" Frequency: " + Nmcli.active.frequency + " MHz"); - appendLog(" Security: " + (Nmcli.active.security || "Open")); - appendLog(" Is Secure: " + (Nmcli.active.isSecure ? "Yes" : "No")); - } else { - appendLog("No active network"); - } - } - } - } - } - } - - // Ethernet Device Management Section - StyledRect { - Layout.fillWidth: true - implicitHeight: ethernetManagementLayout.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - id: ethernetManagementLayout - - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.normal - - StyledText { - text: qsTr("Ethernet Device Management") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Ethernet Devices: %1").arg(Nmcli.ethernetDevices.length) - } - - StyledText { - text: qsTr("Active: %1").arg(Nmcli.activeEthernet ? Nmcli.activeEthernet.interface : "None") - color: Nmcli.activeEthernet ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Refresh Devices") - onClicked: { - appendLog("Refreshing ethernet devices..."); - Nmcli.getEthernetInterfaces((interfaces) => { - appendLog("Found " + Nmcli.ethernetDevices.length + " ethernet devices"); - for (let i = 0; i < Nmcli.ethernetDevices.length; i++) { - const dev = Nmcli.ethernetDevices[i]; - appendLog(" " + (i + 1) + ". " + dev.interface + " - " + dev.state + (dev.connected ? " [Connected]" : "")); - } - if (Nmcli.activeEthernet) { - appendLog("Active ethernet: " + Nmcli.activeEthernet.interface); - } - }); - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("Selected Interface: %1").arg(interfaceSelector.selectedInterface || "None") - } - - StyledText { - visible: interfaceSelector.selectedInterface.length > 0 - text: { - if (!interfaceSelector.selectedInterface) return ""; - const device = Nmcli.ethernetDevices.find(d => d.interface === interfaceSelector.selectedInterface); - if (!device) return ""; - return device.connected ? qsTr("[Connected]") : qsTr("[Disconnected]"); - } - color: { - if (!interfaceSelector.selectedInterface) return Colours.palette.m3onSurface; - const device = Nmcli.ethernetDevices.find(d => d.interface === interfaceSelector.selectedInterface); - if (!device) return Colours.palette.m3onSurface; - return device.connected ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant; - } - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Connect Ethernet") - enabled: interfaceSelector.selectedInterface.length > 0 - onClicked: { - if (interfaceSelector.selectedInterface) { - const device = Nmcli.ethernetDevices.find(d => d.interface === interfaceSelector.selectedInterface); - if (device) { - appendLog("Connecting ethernet: " + interfaceSelector.selectedInterface); - appendLog("Connection name: " + (device.connection || "N/A")); - Nmcli.connectEthernet(device.connection || "", interfaceSelector.selectedInterface, (result) => { - if (result.success) { - appendLog("✓ Ethernet connection initiated"); - appendLog("Refreshing device list..."); - } else { - appendLog("✗ Failed to connect: " + (result.error || "Unknown error")); - } - }); - } else { - appendLog("Device not found in ethernet devices list"); - } - } - } - } - - TextButton { - text: qsTr("Disconnect Ethernet") - enabled: interfaceSelector.selectedInterface.length > 0 - onClicked: { - if (interfaceSelector.selectedInterface) { - const device = Nmcli.ethernetDevices.find(d => d.interface === interfaceSelector.selectedInterface); - if (device && device.connection) { - appendLog("Disconnecting ethernet: " + device.connection); - Nmcli.disconnectEthernet(device.connection, (result) => { - if (result.success) { - appendLog("✓ Ethernet disconnected"); - appendLog("Refreshing device list..."); - } else { - appendLog("✗ Failed to disconnect: " + (result.error || "Unknown error")); - } - }); - } else { - appendLog("No connection name available for this device"); - } - } - } - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.small - - StyledText { - text: qsTr("List All Ethernet Devices") - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("List Devices") - onClicked: { - appendLog("Ethernet Devices:"); - if (Nmcli.ethernetDevices.length === 0) { - appendLog(" No ethernet devices found"); - } else { - for (let i = 0; i < Nmcli.ethernetDevices.length; i++) { - const dev = Nmcli.ethernetDevices[i]; - appendLog(" " + (i + 1) + ". " + dev.interface); - appendLog(" Type: " + dev.type); - appendLog(" State: " + dev.state); - appendLog(" Connection: " + (dev.connection || "None")); - appendLog(" Connected: " + (dev.connected ? "Yes" : "No")); - } - } - } - } - - TextButton { - text: qsTr("Show Active Device") - onClicked: { - if (Nmcli.activeEthernet) { - appendLog("Active Ethernet Device:"); - appendLog(" Interface: " + Nmcli.activeEthernet.interface); - appendLog(" State: " + Nmcli.activeEthernet.state); - appendLog(" Connection: " + (Nmcli.activeEthernet.connection || "None")); - } else { - appendLog("No active ethernet device"); - } - } - } - } - } - } - - // Debug Output Section - StyledRect { - Layout.fillWidth: true - Layout.preferredHeight: 300 - Layout.minimumHeight: 200 - radius: Appearance.rounding.normal - color: Colours.tPalette.m3surfaceContainer - - ColumnLayout { - anchors.fill: parent - anchors.margins: Appearance.padding.large - spacing: Appearance.spacing.small - - RowLayout { - Layout.fillWidth: true - - StyledText { - text: qsTr("Debug Output") - font.pointSize: Appearance.font.size.normal - font.weight: 500 - } - - Item { - Layout.fillWidth: true - } - - TextButton { - text: qsTr("Copy") - onClicked: { - debugOutput.selectAll(); - debugOutput.copy(); - debugOutput.deselect(); - appendLog("Output copied to clipboard"); - } - } - } - - StyledFlickable { - id: debugOutputFlickable - - Layout.fillWidth: true - Layout.fillHeight: true - flickableDirection: Flickable.VerticalFlick - clip: true - - TextEdit { - id: debugOutput - - width: debugOutputFlickable.width - readOnly: true - wrapMode: TextEdit.Wrap - font.family: Appearance.font.family.mono - font.pointSize: Appearance.font.size.smaller - renderType: TextEdit.NativeRendering - textFormat: TextEdit.PlainText - color: "#ffb0ca" // Use primary color - will be set programmatically - - Component.onCompleted: { - color = Colours.palette.m3primary; - appendLog("Debug panel initialized"); - } - - onTextChanged: { - // Ensure color stays set when text changes - color = Colours.palette.m3primary; - // Update content height - debugOutputFlickable.contentHeight = Math.max(implicitHeight, debugOutputFlickable.height); - // Auto-scroll to bottom - Qt.callLater(() => { - if (debugOutputFlickable.contentHeight > debugOutputFlickable.height) { - debugOutputFlickable.contentY = debugOutputFlickable.contentHeight - debugOutputFlickable.height; - } - }); - } - } - } - - StyledScrollBar { - flickable: debugOutputFlickable - policy: ScrollBar.AlwaysOn - } - } - } - } - } - - function appendLog(message: string): void { - const timestamp = new Date().toLocaleTimeString(); - debugOutput.text += `[${timestamp}] ${message}\n`; - } - - function log(message: string): void { - appendLog(message); - } - - Component.onCompleted: { - // Set up debug logger for Nmcli service - Nmcli.setDebugLogger((msg) => { - appendLog("[Nmcli] " + msg); - }); - } -} - diff --git a/modules/controlcenter/dev/DevNavRail.qml b/modules/controlcenter/dev/DevNavRail.qml deleted file mode 100644 index d2f2d57..0000000 --- a/modules/controlcenter/dev/DevNavRail.qml +++ /dev/null @@ -1,194 +0,0 @@ -pragma ComponentBehavior: Bound - -import "." -import ".." -import qs.components -import qs.services -import qs.config -import Quickshell -import QtQuick -import QtQuick.Layouts - -Item { - id: root - - required property ShellScreen screen - required property DevSession session - - implicitWidth: layout.implicitWidth + Appearance.padding.larger * 4 - implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 - - ColumnLayout { - id: layout - - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Appearance.padding.larger * 2 - spacing: Appearance.spacing.normal - - states: State { - name: "expanded" - when: root.session.navExpanded - - PropertyChanges { - layout.spacing: Appearance.spacing.small - menuIcon.opacity: 0 - menuIconExpanded.opacity: 1 - menuIcon.rotation: 180 - menuIconExpanded.rotation: 0 - } - } - - transitions: Transition { - Anim { - properties: "spacing,opacity,rotation" - } - } - - Item { - id: menuBtn - - Layout.topMargin: Appearance.spacing.large - implicitWidth: menuIcon.implicitWidth + menuIcon.anchors.leftMargin * 2 - implicitHeight: menuIcon.implicitHeight + Appearance.padding.normal * 2 - - StateLayer { - radius: Appearance.rounding.small - - function onClicked(): void { - root.session.navExpanded = !root.session.navExpanded; - } - } - - MaterialIcon { - id: menuIcon - - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Appearance.padding.large - - text: "menu" - font.pointSize: Appearance.font.size.large - } - - MaterialIcon { - id: menuIconExpanded - - anchors.fill: menuIcon - text: "menu_open" - font.pointSize: menuIcon.font.pointSize - opacity: 0 - rotation: -180 - } - } - - NavItem { - Layout.topMargin: Appearance.spacing.large * 2 - icon: "wifi" - label: "wireless" - } - - NavItem { - icon: "bug_report" - label: "debug" - } - } - - component NavItem: Item { - id: item - - required property string icon - required property string label - readonly property bool active: root.session.active === label - - implicitWidth: background.implicitWidth - implicitHeight: background.implicitHeight + smallLabel.implicitHeight + smallLabel.anchors.topMargin - - states: State { - name: "expanded" - when: root.session.navExpanded - - PropertyChanges { - expandedLabel.opacity: 1 - smallLabel.opacity: 0 - background.implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2 + expandedLabel.anchors.leftMargin + expandedLabel.implicitWidth - background.implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 - item.implicitHeight: background.implicitHeight - } - } - - transitions: Transition { - Anim { - property: "opacity" - duration: Appearance.anim.durations.small - } - - Anim { - properties: "implicitWidth,implicitHeight" - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - StyledRect { - id: background - - radius: Appearance.rounding.full - color: Qt.alpha(Colours.palette.m3secondaryContainer, item.active ? 1 : 0) - - implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2 - implicitHeight: icon.implicitHeight + Appearance.padding.small - - StateLayer { - color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface - - function onClicked(): void { - root.session.active = item.label; - } - } - - MaterialIcon { - id: icon - - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Appearance.padding.large - - text: item.icon - color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface - font.pointSize: Appearance.font.size.large - fill: item.active ? 1 : 0 - - Behavior on fill { - Anim {} - } - } - - StyledText { - id: expandedLabel - - anchors.left: icon.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Appearance.spacing.normal - - opacity: 0 - text: item.label - color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface - font.capitalization: Font.Capitalize - } - - StyledText { - id: smallLabel - - anchors.horizontalCenter: icon.horizontalCenter - anchors.top: icon.bottom - anchors.topMargin: Appearance.spacing.small / 2 - - text: item.label - font.pointSize: Appearance.font.size.small - font.capitalization: Font.Capitalize - } - } - } -} - diff --git a/modules/controlcenter/dev/DevPanes.qml b/modules/controlcenter/dev/DevPanes.qml deleted file mode 100644 index 6b5ce06..0000000 --- a/modules/controlcenter/dev/DevPanes.qml +++ /dev/null @@ -1,70 +0,0 @@ -pragma ComponentBehavior: Bound - -import "." -import ".." -import qs.components -import qs.services -import qs.config -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts - -ClippingRectangle { - id: root - - required property DevSession session - - color: "transparent" - - ColumnLayout { - id: layout - - spacing: 0 - y: -root.session.activeIndex * root.height - - Pane { - index: 0 - sourceComponent: DevWirelessPane { - session: root.session - } - } - - Pane { - index: 1 - sourceComponent: DevDebugPane { - session: root.session - } - } - - Behavior on y { - Anim {} - } - } - - component Pane: Item { - id: pane - - required property int index - property alias sourceComponent: loader.sourceComponent - - implicitWidth: root.width - implicitHeight: root.height - - Loader { - id: loader - - anchors.fill: parent - clip: true - asynchronous: true - active: { - if (root.session.activeIndex === pane.index) - return true; - - const ly = -layout.y; - const ty = pane.index * root.height; - return ly + root.height > ty && ly < ty + root.height; - } - } - } -} - diff --git a/modules/controlcenter/dev/DevSession.qml b/modules/controlcenter/dev/DevSession.qml deleted file mode 100644 index d911386..0000000 --- a/modules/controlcenter/dev/DevSession.qml +++ /dev/null @@ -1,23 +0,0 @@ -import QtQuick - -QtObject { - readonly property list panes: ["wireless", "debug"] - - required property var root - property bool floating: false - property string active: panes[0] - property int activeIndex: 0 - property bool navExpanded: false - - component Network: QtObject { - property var active - property bool showPasswordDialog: false - property var pendingNetwork - } - - readonly property Network network: Network {} - - onActiveChanged: activeIndex = panes.indexOf(active) - onActiveIndexChanged: active = panes[activeIndex] -} - diff --git a/modules/controlcenter/dev/DevWindowFactory.qml b/modules/controlcenter/dev/DevWindowFactory.qml deleted file mode 100644 index 5682588..0000000 --- a/modules/controlcenter/dev/DevWindowFactory.qml +++ /dev/null @@ -1,62 +0,0 @@ -pragma Singleton - -import "." -import qs.components -import qs.services -import Quickshell -import QtQuick - -Singleton { - id: root - - function create(parent: Item, props: var): void { - devControlCenter.createObject(parent ?? dummy, props); - } - - QtObject { - id: dummy - } - - Component { - id: devControlCenter - - FloatingWindow { - id: win - - property alias active: cc.active - property alias navExpanded: cc.navExpanded - - color: Colours.tPalette.m3surface - - onVisibleChanged: { - if (!visible) - destroy(); - } - - minimumSize.width: 1000 - minimumSize.height: 600 - - implicitWidth: cc.implicitWidth - implicitHeight: cc.implicitHeight - - title: qsTr("Dev Panel - Wireless") - - DevControlCenter { - id: cc - - anchors.fill: parent - screen: win.screen - floating: true - - function close(): void { - win.destroy(); - } - } - - Behavior on color { - CAnim {} - } - } - } -} - diff --git a/modules/controlcenter/dev/DevWindowTitle.qml b/modules/controlcenter/dev/DevWindowTitle.qml deleted file mode 100644 index 9395532..0000000 --- a/modules/controlcenter/dev/DevWindowTitle.qml +++ /dev/null @@ -1,53 +0,0 @@ -import "." -import qs.components -import qs.services -import qs.config -import Quickshell -import QtQuick - -StyledRect { - id: root - - required property ShellScreen screen - required property DevSession session - - implicitHeight: text.implicitHeight + Appearance.padding.normal - color: Colours.tPalette.m3surfaceContainer - - StyledText { - id: text - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - - text: qsTr("Dev Panel - %1").arg(root.session.active.slice(0, 1).toUpperCase() + root.session.active.slice(1)) - font.capitalization: Font.Capitalize - font.pointSize: Appearance.font.size.larger - font.weight: 500 - } - - Item { - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Appearance.padding.normal - - implicitWidth: implicitHeight - implicitHeight: closeIcon.implicitHeight + Appearance.padding.small - - StateLayer { - radius: Appearance.rounding.full - - function onClicked(): void { - QsWindow.window.destroy(); - } - } - - MaterialIcon { - id: closeIcon - - anchors.centerIn: parent - text: "close" - } - } -} - diff --git a/modules/controlcenter/dev/DevWirelessPane.qml b/modules/controlcenter/dev/DevWirelessPane.qml deleted file mode 100644 index feb0ce7..0000000 --- a/modules/controlcenter/dev/DevWirelessPane.qml +++ /dev/null @@ -1,68 +0,0 @@ -pragma ComponentBehavior: Bound - -import "." -import ".." -import qs.components -import qs.components.effects -import qs.components.containers -import qs.config -import Quickshell.Widgets -import QtQuick -import QtQuick.Layouts - -RowLayout { - id: root - - required property DevSession session - - anchors.fill: parent - - spacing: 0 - - Item { - Layout.preferredWidth: Math.floor(parent.width * 0.4) - Layout.minimumWidth: 420 - Layout.fillHeight: true - - // Blank placeholder for wireless list - Item { - anchors.fill: parent - anchors.margins: Appearance.padding.large + Appearance.padding.normal - anchors.leftMargin: Appearance.padding.large - anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2 - } - - InnerBorder { - leftThickness: 0 - rightThickness: Appearance.padding.normal / 2 - } - } - - Item { - Layout.fillWidth: true - Layout.fillHeight: true - - ClippingRectangle { - anchors.fill: parent - anchors.margins: Appearance.padding.normal - anchors.leftMargin: 0 - anchors.rightMargin: Appearance.padding.normal / 2 - - radius: rightBorder.innerRadius - color: "transparent" - - // Blank placeholder for settings/details area - Item { - anchors.fill: parent - anchors.margins: Appearance.padding.large * 2 - } - } - - InnerBorder { - id: rightBorder - - leftThickness: Appearance.padding.normal / 2 - } - } -} - diff --git a/modules/utilities/cards/Toggles.qml b/modules/utilities/cards/Toggles.qml index ccf1c7d..d3ad51e 100644 --- a/modules/utilities/cards/Toggles.qml +++ b/modules/utilities/cards/Toggles.qml @@ -3,7 +3,6 @@ import qs.components.controls import qs.services import qs.config import qs.modules.controlcenter -import "../../controlcenter/dev" import Quickshell import Quickshell.Bluetooth import QtQuick @@ -94,17 +93,6 @@ StyledRect { onClicked: VPN.toggle() } - Toggle { - icon: "bug_report" - inactiveOnColour: Colours.palette.m3onSurfaceVariant - toggle: false - onClicked: { - root.visibilities.utilities = false; - DevWindowFactory.create(null, { - screen: QsWindow.window?.screen ?? null - }); - } - } } } -- cgit v1.2.3-freya From 21e715468e9800a73c731921c27177731033d2ec Mon Sep 17 00:00:00 2001 From: ATMDA Date: Sun, 16 Nov 2025 09:45:05 -0500 Subject: controlcenter: changed to popout vs floating to match the other settings buttons (fixed issues with resizing) --- modules/bar/components/Settings.qml | 4 +- modules/bar/components/SettingsIcon.qml | 4 +- modules/controlcenter/NavRail.qml | 119 +------------------------------- modules/drawers/Panels.qml | 1 + modules/utilities/Content.qml | 2 + modules/utilities/Wrapper.qml | 2 + modules/utilities/cards/Toggles.qml | 5 +- 7 files changed, 14 insertions(+), 123 deletions(-) (limited to 'modules/utilities') diff --git a/modules/bar/components/Settings.qml b/modules/bar/components/Settings.qml index e92fc46..0eceea7 100644 --- a/modules/bar/components/Settings.qml +++ b/modules/bar/components/Settings.qml @@ -21,7 +21,9 @@ Item { radius: Appearance.rounding.full function onClicked(): void { - WindowFactory.create(); + WindowFactory.create(null, { + active: "appearance" + }); } } diff --git a/modules/bar/components/SettingsIcon.qml b/modules/bar/components/SettingsIcon.qml index e92fc46..0eceea7 100644 --- a/modules/bar/components/SettingsIcon.qml +++ b/modules/bar/components/SettingsIcon.qml @@ -21,7 +21,9 @@ Item { radius: Appearance.rounding.full function onClicked(): void { - WindowFactory.create(); + WindowFactory.create(null, { + active: "appearance" + }); } } diff --git a/modules/controlcenter/NavRail.qml b/modules/controlcenter/NavRail.qml index 234f447..8432f17 100644 --- a/modules/controlcenter/NavRail.qml +++ b/modules/controlcenter/NavRail.qml @@ -30,129 +30,12 @@ Item { PropertyChanges { layout.spacing: Appearance.spacing.small - menuIcon.opacity: 0 - menuIconExpanded.opacity: 1 - menuIcon.rotation: 180 - menuIconExpanded.rotation: 0 } } transitions: Transition { Anim { - properties: "spacing,opacity,rotation" - } - } - - Item { - id: menuBtn - - Layout.topMargin: Appearance.spacing.large - implicitWidth: menuIcon.implicitWidth + menuIcon.anchors.leftMargin * 2 - implicitHeight: menuIcon.implicitHeight + Appearance.padding.normal * 2 - - StateLayer { - radius: Appearance.rounding.small - - function onClicked(): void { - root.session.navExpanded = !root.session.navExpanded; - } - } - - MaterialIcon { - id: menuIcon - - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Appearance.padding.large - - text: "menu" - font.pointSize: Appearance.font.size.large - } - - MaterialIcon { - id: menuIconExpanded - - anchors.fill: menuIcon - text: "menu_open" - font.pointSize: menuIcon.font.pointSize - opacity: 0 - rotation: -180 - } - } - - Loader { - asynchronous: true - active: !root.session.floating - visible: active - - sourceComponent: StyledRect { - readonly property int nonAnimWidth: normalWinIcon.implicitWidth + (root.session.navExpanded ? normalWinLabel.anchors.leftMargin + normalWinLabel.implicitWidth : 0) + normalWinIcon.anchors.leftMargin * 2 - - implicitWidth: nonAnimWidth - implicitHeight: root.session.navExpanded ? normalWinIcon.implicitHeight + Appearance.padding.normal * 2 : nonAnimWidth - - color: Colours.palette.m3primaryContainer - radius: Appearance.rounding.small - - StateLayer { - id: normalWinState - - color: Colours.palette.m3onPrimaryContainer - - function onClicked(): void { - root.session.root.close(); - WindowFactory.create(null, { - screen: root.screen, - active: root.session.active, - navExpanded: root.session.navExpanded - }); - } - } - - MaterialIcon { - id: normalWinIcon - - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Appearance.padding.large - - text: "select_window" - color: Colours.palette.m3onPrimaryContainer - font.pointSize: Appearance.font.size.large - fill: 1 - } - - StyledText { - id: normalWinLabel - - anchors.left: normalWinIcon.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Appearance.spacing.normal - - text: qsTr("Float window") - color: Colours.palette.m3onPrimaryContainer - opacity: root.session.navExpanded ? 1 : 0 - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.small - } - } - } - - Behavior on implicitWidth { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - Behavior on implicitHeight { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } + properties: "spacing" } } diff --git a/modules/drawers/Panels.qml b/modules/drawers/Panels.qml index 4ce1182..7705732 100644 --- a/modules/drawers/Panels.qml +++ b/modules/drawers/Panels.qml @@ -109,6 +109,7 @@ Item { visibilities: root.visibilities sidebar: sidebar + popouts: popouts anchors.bottom: parent.bottom anchors.right: parent.right diff --git a/modules/utilities/Content.qml b/modules/utilities/Content.qml index d5be824..902656d 100644 --- a/modules/utilities/Content.qml +++ b/modules/utilities/Content.qml @@ -8,6 +8,7 @@ Item { required property var props required property var visibilities + required property Item popouts implicitWidth: layout.implicitWidth implicitHeight: layout.implicitHeight @@ -28,6 +29,7 @@ Item { Toggles { visibilities: root.visibilities + popouts: root.popouts } } diff --git a/modules/utilities/Wrapper.qml b/modules/utilities/Wrapper.qml index dd784bc..77178e3 100644 --- a/modules/utilities/Wrapper.qml +++ b/modules/utilities/Wrapper.qml @@ -10,6 +10,7 @@ Item { required property var visibilities required property Item sidebar + required property Item popouts readonly property PersistentProperties props: PersistentProperties { property bool recordingListExpanded: false @@ -89,6 +90,7 @@ Item { implicitWidth: root.implicitWidth - Appearance.padding.large * 2 props: root.props visibilities: root.visibilities + popouts: root.popouts } } } diff --git a/modules/utilities/cards/Toggles.qml b/modules/utilities/cards/Toggles.qml index d3ad51e..71f4d1d 100644 --- a/modules/utilities/cards/Toggles.qml +++ b/modules/utilities/cards/Toggles.qml @@ -12,6 +12,7 @@ StyledRect { id: root required property var visibilities + required property Item popouts Layout.fillWidth: true implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 @@ -67,9 +68,7 @@ StyledRect { toggle: false onClicked: { root.visibilities.utilities = false; - WindowFactory.create(null, { - screen: QsWindow.window?.screen ?? null - }); + root.popouts.detach("appearance"); } } -- cgit v1.2.3-freya From 59c906d6508ccbc6f4731f222bb56a9a5e9f5345 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Sun, 16 Nov 2025 13:09:09 -0500 Subject: controlcenter: appearance pane async loader --- modules/bar/components/Settings.qml | 2 +- modules/bar/components/SettingsIcon.qml | 2 +- .../controlcenter/appearance/AppearancePane.qml | 303 +++++++++++---------- modules/utilities/cards/Toggles.qml | 2 +- 4 files changed, 165 insertions(+), 144 deletions(-) (limited to 'modules/utilities') diff --git a/modules/bar/components/Settings.qml b/modules/bar/components/Settings.qml index 0eceea7..7cd18be 100644 --- a/modules/bar/components/Settings.qml +++ b/modules/bar/components/Settings.qml @@ -22,7 +22,7 @@ Item { function onClicked(): void { WindowFactory.create(null, { - active: "appearance" + active: "network" }); } } diff --git a/modules/bar/components/SettingsIcon.qml b/modules/bar/components/SettingsIcon.qml index 0eceea7..7cd18be 100644 --- a/modules/bar/components/SettingsIcon.qml +++ b/modules/bar/components/SettingsIcon.qml @@ -22,7 +22,7 @@ Item { function onClicked(): void { WindowFactory.create(null, { - active: "appearance" + active: "network" }); } } diff --git a/modules/controlcenter/appearance/AppearancePane.qml b/modules/controlcenter/appearance/AppearancePane.qml index 13ebf55..09cb04f 100644 --- a/modules/controlcenter/appearance/AppearancePane.qml +++ b/modules/controlcenter/appearance/AppearancePane.qml @@ -538,65 +538,72 @@ RowLayout { title: qsTr("Material font family") expanded: true - StyledListView { + Loader { Layout.fillWidth: true - Layout.preferredHeight: Math.min(contentHeight, 300) - - clip: true - spacing: Appearance.spacing.small / 2 - model: Qt.fontFamilies() - - 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(); + Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 + asynchronous: true + active: materialFontSection.expanded + + sourceComponent: StyledListView { + id: materialFontList + property alias contentHeight: materialFontList.contentHeight + + clip: true + spacing: Appearance.spacing.small / 2 + model: Qt.fontFamilies() + + 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 + RowLayout { + id: fontFamilyMaterialRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal - spacing: Appearance.spacing.normal + spacing: Appearance.spacing.normal - StyledText { - text: modelData - font.pointSize: Appearance.font.size.normal - } + StyledText { + text: modelData + font.pointSize: Appearance.font.size.normal + } - Item { - Layout.fillWidth: true - } + Item { + Layout.fillWidth: true + } - Loader { - active: isCurrent - asynchronous: true + Loader { + active: isCurrent + asynchronous: true - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } } } - } - implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2 + implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2 + } } } } @@ -606,65 +613,72 @@ RowLayout { title: qsTr("Monospace font family") expanded: false - StyledListView { + Loader { Layout.fillWidth: true - Layout.preferredHeight: Math.min(contentHeight, 300) - - clip: true - spacing: Appearance.spacing.small / 2 - model: Qt.fontFamilies() - - 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(); + Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 + asynchronous: true + active: monoFontSection.expanded + + sourceComponent: StyledListView { + id: monoFontList + property alias contentHeight: monoFontList.contentHeight + + clip: true + spacing: Appearance.spacing.small / 2 + model: Qt.fontFamilies() + + 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 + RowLayout { + id: fontFamilyMonoRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal - spacing: Appearance.spacing.normal + spacing: Appearance.spacing.normal - StyledText { - text: modelData - font.pointSize: Appearance.font.size.normal - } + StyledText { + text: modelData + font.pointSize: Appearance.font.size.normal + } - Item { - Layout.fillWidth: true - } + Item { + Layout.fillWidth: true + } - Loader { - active: isCurrent - asynchronous: true + Loader { + active: isCurrent + asynchronous: true - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } } } - } - implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2 + implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2 + } } } } @@ -674,65 +688,72 @@ RowLayout { title: qsTr("Sans-serif font family") expanded: false - StyledListView { + Loader { Layout.fillWidth: true - Layout.preferredHeight: Math.min(contentHeight, 300) - - clip: true - spacing: Appearance.spacing.small / 2 - model: Qt.fontFamilies() - - 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(); + Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 + asynchronous: true + active: sansFontSection.expanded + + sourceComponent: StyledListView { + id: sansFontList + property alias contentHeight: sansFontList.contentHeight + + clip: true + spacing: Appearance.spacing.small / 2 + model: Qt.fontFamilies() + + 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 + RowLayout { + id: fontFamilySansRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.normal + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal - spacing: Appearance.spacing.normal + spacing: Appearance.spacing.normal - StyledText { - text: modelData - font.pointSize: Appearance.font.size.normal - } + StyledText { + text: modelData + font.pointSize: Appearance.font.size.normal + } - Item { - Layout.fillWidth: true - } + Item { + Layout.fillWidth: true + } - Loader { - active: isCurrent - asynchronous: true + Loader { + active: isCurrent + asynchronous: true - sourceComponent: MaterialIcon { - text: "check" - color: Colours.palette.m3onSurfaceVariant - font.pointSize: Appearance.font.size.large + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } } } - } - implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2 + implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2 + } } } } diff --git a/modules/utilities/cards/Toggles.qml b/modules/utilities/cards/Toggles.qml index 71f4d1d..51e991e 100644 --- a/modules/utilities/cards/Toggles.qml +++ b/modules/utilities/cards/Toggles.qml @@ -68,7 +68,7 @@ StyledRect { toggle: false onClicked: { root.visibilities.utilities = false; - root.popouts.detach("appearance"); + root.popouts.detach("network"); } } -- cgit v1.2.3-freya