diff --git a/components/controls/CollapsibleSection.qml b/components/controls/CollapsibleSection.qml index 0e4c3dcf..9a4c4027 100644 --- a/components/controls/CollapsibleSection.qml +++ b/components/controls/CollapsibleSection.qml @@ -53,6 +53,7 @@ ColumnLayout { rotation: root.expanded ? 180 : 0 color: Colours.palette.m3onSurfaceVariant font.pointSize: Appearance.font.size.normal + Behavior on rotation { Anim { duration: Appearance.anim.durations.small diff --git a/components/controls/StyledScrollBar.qml b/components/controls/StyledScrollBar.qml index c2831da4..7ec537d0 100644 --- a/components/controls/StyledScrollBar.qml +++ b/components/controls/StyledScrollBar.qml @@ -36,24 +36,6 @@ ScrollBar { } } - // Sync nonAnimPosition with flickable when not animating - Connections { - target: flickable - function onContentYChanged() { - if (!animating && !fullMouse.pressed) { - _updatingFromFlickable = true; - const contentHeight = flickable.contentHeight; - const height = flickable.height; - if (contentHeight > height) { - nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); - } else { - nonAnimPosition = 0; - } - _updatingFromFlickable = false; - } - } - } - Component.onCompleted: { if (flickable) { const contentHeight = flickable.contentHeight; @@ -96,15 +78,34 @@ ScrollBar { } } + // Sync nonAnimPosition with flickable when not animating Connections { - target: root.flickable + function onContentYChanged() { + if (!animating && !fullMouse.pressed) { + _updatingFromFlickable = true; + const contentHeight = flickable.contentHeight; + const height = flickable.height; + if (contentHeight > height) { + nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); + } else { + nonAnimPosition = 0; + } + _updatingFromFlickable = false; + } + } + target: flickable + } + + Connections { function onMovingChanged(): void { if (root.flickable.moving) root.shouldBeActive = true; else hideDelay.restart(); } + + target: root.flickable } Timer { diff --git a/components/controls/StyledTextField.qml b/components/controls/StyledTextField.qml index 60bcff25..6f3532dc 100644 --- a/components/controls/StyledTextField.qml +++ b/components/controls/StyledTextField.qml @@ -28,8 +28,6 @@ TextField { radius: Appearance.rounding.normal Connections { - target: root - function onCursorPositionChanged(): void { if (root.activeFocus && root.cursorVisible) { cursor.opacity = 1; @@ -37,6 +35,8 @@ TextField { enableBlink.restart(); } } + + target: root } Timer { diff --git a/components/controls/ToggleButton.qml b/components/controls/ToggleButton.qml index 8286ccae..b05e7f5a 100644 --- a/components/controls/ToggleButton.qml +++ b/components/controls/ToggleButton.qml @@ -18,31 +18,30 @@ StyledRect { property real horizontalPadding: Appearance.padding.large property real verticalPadding: Appearance.padding.normal property string tooltip: "" - property bool hovered: false + signal clicked Component.onCompleted: { hovered = toggleStateLayer.containsMouse; } + Layout.preferredWidth: implicitWidth + (toggleStateLayer.pressed ? Appearance.padding.normal * 2 : toggled ? Appearance.padding.small * 2 : 0) + implicitWidth: toggleBtnInner.implicitWidth + horizontalPadding * 2 + implicitHeight: toggleBtnIcon.implicitHeight + verticalPadding * 2 + radius: toggled || toggleStateLayer.pressed ? Appearance.rounding.small : Math.min(width, height) / 2 * Math.min(1, Appearance.rounding.scale) + color: toggled ? Colours.palette[`m3${accent.toLowerCase()}`] : Colours.palette[`m3${accent.toLowerCase()}Container`] Connections { - target: toggleStateLayer function onContainsMouseChanged() { const newHovered = toggleStateLayer.containsMouse; if (hovered !== newHovered) { hovered = newHovered; } } + + target: toggleStateLayer } - Layout.preferredWidth: implicitWidth + (toggleStateLayer.pressed ? Appearance.padding.normal * 2 : toggled ? Appearance.padding.small * 2 : 0) - implicitWidth: toggleBtnInner.implicitWidth + horizontalPadding * 2 - implicitHeight: toggleBtnIcon.implicitHeight + verticalPadding * 2 - - radius: toggled || toggleStateLayer.pressed ? Appearance.rounding.small : Math.min(width, height) / 2 * Math.min(1, Appearance.rounding.scale) - color: toggled ? Colours.palette[`m3${accent.toLowerCase()}`] : Colours.palette[`m3${accent.toLowerCase()}Container`] - StateLayer { id: toggleStateLayer diff --git a/components/controls/Tooltip.qml b/components/controls/Tooltip.qml index 8d16fd48..ab9401f6 100644 --- a/components/controls/Tooltip.qml +++ b/components/controls/Tooltip.qml @@ -90,23 +90,9 @@ Popup { Qt.callLater(updatePosition); } } - Connections { - target: root.target - function onXChanged() { - if (root.tooltipVisible) - root.updatePosition(); - } - function onYChanged() { - if (root.tooltipVisible) - root.updatePosition(); - } - function onWidthChanged() { - if (root.tooltipVisible) - root.updatePosition(); - } - function onHeightChanged() { - if (root.tooltipVisible) - root.updatePosition(); + Component.onCompleted: { + if (tooltipVisible) { + updatePosition(); } } @@ -130,24 +116,6 @@ Popup { } } - // Monitor hover state - Connections { - target: root.target - function onHoveredChanged() { - if (target.hovered) { - showTimer.start(); - if (timeout > 0) { - hideTimer.stop(); - hideTimer.start(); - } - } else { - showTimer.stop(); - hideTimer.stop(); - tooltipVisible = false; - } - } - } - contentItem: StyledRect { id: tooltipRect @@ -177,9 +145,43 @@ Popup { } } - Component.onCompleted: { - if (tooltipVisible) { - updatePosition(); + Connections { + function onXChanged() { + if (root.tooltipVisible) + root.updatePosition(); } + function onYChanged() { + if (root.tooltipVisible) + root.updatePosition(); + } + function onWidthChanged() { + if (root.tooltipVisible) + root.updatePosition(); + } + function onHeightChanged() { + if (root.tooltipVisible) + root.updatePosition(); + } + + target: root.target + } + + // Monitor hover state + Connections { + function onHoveredChanged() { + if (target.hovered) { + showTimer.start(); + if (timeout > 0) { + hideTimer.stop(); + hideTimer.start(); + } + } else { + showTimer.stop(); + hideTimer.stop(); + tooltipVisible = false; + } + } + + target: root.target } } diff --git a/components/filedialog/CurrentItem.qml b/components/filedialog/CurrentItem.qml index bb87133c..a33523b7 100644 --- a/components/filedialog/CurrentItem.qml +++ b/components/filedialog/CurrentItem.qml @@ -80,12 +80,12 @@ Item { anchors.bottomMargin: Appearance.padding.normal - Appearance.padding.small Connections { - target: root - function onCurrentItemChanged(): void { if (root.currentItem) content.text = qsTr(`"%1" selected`).arg(root.currentItem.modelData.name); } + + target: root } } } diff --git a/components/filedialog/FolderContents.qml b/components/filedialog/FolderContents.qml index 00d7a3d9..12d59598 100644 --- a/components/filedialog/FolderContents.qml +++ b/components/filedialog/FolderContents.qml @@ -129,16 +129,16 @@ Item { clip: true StateLayer { + function onClicked(): void { + view.currentIndex = item.index; + } + onDoubleClicked: { if (item.modelData.isDir) root.dialog.cwd.push(item.modelData.name); else if (root.dialog.selectionValid) root.dialog.accepted(item.modelData.path); } - - function onClicked(): void { - view.currentIndex = item.index; - } } CachingIconImage { diff --git a/components/images/CachingImage.qml b/components/images/CachingImage.qml index e8f957a7..83bd5e47 100644 --- a/components/images/CachingImage.qml +++ b/components/images/CachingImage.qml @@ -12,11 +12,11 @@ Image { fillMode: Image.PreserveAspectCrop Connections { - target: QsWindow.window - function onDevicePixelRatioChanged(): void { manager.updateSource(); } + + target: QsWindow.window } CachingImageManager { diff --git a/modules/BatteryMonitor.qml b/modules/BatteryMonitor.qml index d24cff27..9d6e4e84 100644 --- a/modules/BatteryMonitor.qml +++ b/modules/BatteryMonitor.qml @@ -10,8 +10,6 @@ Scope { readonly property list warnLevels: [...Config.general.battery.warnLevels].sort((a, b) => b.level - a.level) Connections { - target: UPower - function onOnBatteryChanged(): void { if (UPower.onBattery) { if (Config.utilities.toasts.chargingChanged) @@ -23,11 +21,11 @@ Scope { level.warned = false; } } + + target: UPower } Connections { - target: UPower.displayDevice - function onPercentageChanged(): void { if (!UPower.onBattery) return; @@ -45,6 +43,8 @@ Scope { hibernateTimer.start(); } } + + target: UPower.displayDevice } Timer { diff --git a/modules/Shortcuts.qml b/modules/Shortcuts.qml index 3bf20a4f..a769e160 100644 --- a/modules/Shortcuts.qml +++ b/modules/Shortcuts.qml @@ -93,8 +93,6 @@ Scope { } IpcHandler { - target: "drawers" - function toggle(drawer: string): void { if (list().split("\n").includes(drawer)) { if (root.hasFullscreen && ["launcher", "session", "dashboard"].includes(drawer)) @@ -110,19 +108,19 @@ Scope { const visibilities = Visibilities.getForActive(); return Object.keys(visibilities).filter(k => typeof visibilities[k] === "boolean").join("\n"); } + + target: "drawers" } IpcHandler { - target: "controlCenter" - function open(): void { WindowFactory.create(); } + + target: "controlCenter" } IpcHandler { - target: "toaster" - function info(title: string, message: string, icon: string): void { Toaster.toast(title, message, icon, Toast.Info); } @@ -138,5 +136,7 @@ Scope { function error(title: string, message: string, icon: string): void { Toaster.toast(title, message, icon, Toast.Error); } + + target: "toaster" } } diff --git a/modules/areapicker/AreaPicker.qml b/modules/areapicker/AreaPicker.qml index 308b7d23..fc0eaab0 100644 --- a/modules/areapicker/AreaPicker.qml +++ b/modules/areapicker/AreaPicker.qml @@ -48,8 +48,6 @@ Scope { } IpcHandler { - target: "picker" - function open(): void { root.freeze = false; root.closing = false; @@ -77,6 +75,8 @@ Scope { root.clipboardOnly = true; root.activeAsync = true; } + + target: "picker" } CustomShortcut { diff --git a/modules/background/Background.qml b/modules/background/Background.qml index 06a09529..e932f381 100644 --- a/modules/background/Background.qml +++ b/modules/background/Background.qml @@ -68,6 +68,7 @@ Loader { states: [ State { name: "top-left" + AnchorChanges { target: clockLoader anchors.top: parent.top @@ -76,6 +77,7 @@ Loader { }, State { name: "top-center" + AnchorChanges { target: clockLoader anchors.top: parent.top @@ -84,6 +86,7 @@ Loader { }, State { name: "top-right" + AnchorChanges { target: clockLoader anchors.top: parent.top @@ -92,6 +95,7 @@ Loader { }, State { name: "middle-left" + AnchorChanges { target: clockLoader anchors.verticalCenter: parent.verticalCenter @@ -100,6 +104,7 @@ Loader { }, State { name: "middle-center" + AnchorChanges { target: clockLoader anchors.verticalCenter: parent.verticalCenter @@ -108,6 +113,7 @@ Loader { }, State { name: "middle-right" + AnchorChanges { target: clockLoader anchors.verticalCenter: parent.verticalCenter @@ -116,6 +122,7 @@ Loader { }, State { name: "bottom-left" + AnchorChanges { target: clockLoader anchors.bottom: parent.bottom @@ -124,6 +131,7 @@ Loader { }, State { name: "bottom-center" + AnchorChanges { target: clockLoader anchors.bottom: parent.bottom @@ -132,6 +140,7 @@ Loader { }, State { name: "bottom-right" + AnchorChanges { target: clockLoader anchors.bottom: parent.bottom diff --git a/modules/bar/components/Power.qml b/modules/bar/components/Power.qml index 917bdf7f..dc9ef693 100644 --- a/modules/bar/components/Power.qml +++ b/modules/bar/components/Power.qml @@ -14,16 +14,15 @@ Item { StateLayer { // Cursed workaround to make the height larger than the parent + function onClicked(): void { + root.visibilities.session = !root.visibilities.session; + } + anchors.fill: undefined anchors.centerIn: parent implicitWidth: implicitHeight implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 - radius: Appearance.rounding.full - - function onClicked(): void { - root.visibilities.session = !root.visibilities.session; - } } MaterialIcon { diff --git a/modules/bar/components/Settings.qml b/modules/bar/components/Settings.qml index 5d562cef..f193c7c1 100644 --- a/modules/bar/components/Settings.qml +++ b/modules/bar/components/Settings.qml @@ -13,18 +13,17 @@ Item { StateLayer { // Cursed workaround to make the height larger than the parent - anchors.fill: undefined - anchors.centerIn: parent - implicitWidth: implicitHeight - implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 - - radius: Appearance.rounding.full - function onClicked(): void { WindowFactory.create(null, { active: "network" }); } + + anchors.fill: undefined + anchors.centerIn: parent + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 + radius: Appearance.rounding.full } MaterialIcon { diff --git a/modules/bar/components/SettingsIcon.qml b/modules/bar/components/SettingsIcon.qml index 5d562cef..f193c7c1 100644 --- a/modules/bar/components/SettingsIcon.qml +++ b/modules/bar/components/SettingsIcon.qml @@ -13,18 +13,17 @@ Item { StateLayer { // Cursed workaround to make the height larger than the parent - anchors.fill: undefined - anchors.centerIn: parent - implicitWidth: implicitHeight - implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 - - radius: Appearance.rounding.full - function onClicked(): void { WindowFactory.create(null, { active: "network" }); } + + anchors.fill: undefined + anchors.centerIn: parent + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 + radius: Appearance.rounding.full } MaterialIcon { diff --git a/modules/bar/components/workspaces/SpecialWorkspaces.qml b/modules/bar/components/workspaces/SpecialWorkspaces.qml index 555bb3b4..03394463 100644 --- a/modules/bar/components/workspaces/SpecialWorkspaces.qml +++ b/modules/bar/components/workspaces/SpecialWorkspaces.qml @@ -134,8 +134,6 @@ Item { // Hacky thing cause modelData gets destroyed before the remove anim finishes Connections { - target: ws.modelData - function onIdChanged(): void { if (ws.modelData) ws.wsId = ws.modelData.id; @@ -150,15 +148,17 @@ Item { if (ws.modelData) ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0; } + + target: ws.modelData } Connections { - target: Config.bar.workspaces - function onShowWindowsOnSpecialWorkspacesChanged(): void { if (ws.modelData) ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0; } + + target: Config.bar.workspaces } Loader { diff --git a/modules/bar/popouts/Content.qml b/modules/bar/popouts/Content.qml index 24e7909e..f866b45c 100644 --- a/modules/bar/popouts/Content.qml +++ b/modules/bar/popouts/Content.qml @@ -63,7 +63,6 @@ Item { } Connections { - target: root.wrapper function onCurrentNameChanged() { // Update network immediately when password popout becomes active if (root.wrapper.currentName === "wirelesspassword") { @@ -81,10 +80,11 @@ Item { }, 100); } } + + target: root.wrapper } Connections { - target: networkPopout function onItemChanged() { // When network popout loads, update password popout if it's active if (root.wrapper.currentName === "wirelesspassword" && passwordPopout.item) { @@ -95,6 +95,8 @@ Item { }); } } + + target: networkPopout } } @@ -144,14 +146,14 @@ Item { sourceComponent: trayMenuComp Connections { - target: root.wrapper - function onHasCurrentChanged(): void { if (root.wrapper.hasCurrent && trayMenu.shouldBeActive) { trayMenu.sourceComponent = null; trayMenu.sourceComponent = trayMenuComp; } } + + target: root.wrapper } Component { diff --git a/modules/bar/popouts/Network.qml b/modules/bar/popouts/Network.qml index 367b9ab8..91991fcb 100644 --- a/modules/bar/popouts/Network.qml +++ b/modules/bar/popouts/Network.qml @@ -334,8 +334,6 @@ ColumnLayout { } Connections { - target: Nmcli - function onActiveChanged(): void { if (Nmcli.active && root.connectingToSsid === Nmcli.active.ssid) { root.connectingToSsid = ""; @@ -354,10 +352,11 @@ ColumnLayout { if (!Nmcli.scanning) scanIcon.rotation = 0; } + + target: Nmcli } Connections { - target: root.wrapper function onCurrentNameChanged(): void { // Clear password network when leaving password dialog if (root.wrapper.currentName !== "wirelesspassword" && root.showPasswordDialog) { @@ -365,6 +364,8 @@ ColumnLayout { root.passwordNetwork = null; } } + + target: root.wrapper } component Toggle: RowLayout { diff --git a/modules/bar/popouts/WirelessPassword.qml b/modules/bar/popouts/WirelessPassword.qml index c6b37b63..0c0f301f 100644 --- a/modules/bar/popouts/WirelessPassword.qml +++ b/modules/bar/popouts/WirelessPassword.qml @@ -69,43 +69,9 @@ ColumnLayout { } } - Connections { - target: root.wrapper - function onCurrentNameChanged() { - if (root.wrapper.currentName === "wirelesspassword") { - // Update network when popout becomes active - Qt.callLater(() => { - // Try to get network from parent Content's networkPopout - const content = root.parent?.parent?.parent; - if (content) { - const networkPopout = content.children.find(c => c.name === "network"); - if (networkPopout && networkPopout.item) { - root.network = networkPopout.item.passwordNetwork; - } - } - // Force focus to password container when popout becomes active - // Use Timer for actual delay to ensure dialog is fully rendered - focusTimer.start(); - }); - } - } - } - - Timer { - id: focusTimer - - interval: 150 - onTriggered: { - root.forceActiveFocus(); - passwordContainer.forceActiveFocus(); - } - } - spacing: Appearance.spacing.normal - implicitWidth: 400 implicitHeight: content.implicitHeight + Appearance.padding.large * 2 - visible: shouldBeVisible || isClosing enabled: shouldBeVisible && !isClosing focus: enabled @@ -126,16 +92,49 @@ ColumnLayout { Keys.onEscapePressed: closeDialog() + Connections { + function onCurrentNameChanged() { + if (root.wrapper.currentName === "wirelesspassword") { + // Update network when popout becomes active + Qt.callLater(() => { + // Try to get network from parent Content's networkPopout + const content = root.parent?.parent?.parent; + if (content) { + const networkPopout = content.children.find(c => c.name === "network"); + if (networkPopout && networkPopout.item) { + root.network = networkPopout.item.passwordNetwork; + } + } + // Force focus to password container when popout becomes active + // Use Timer for actual delay to ensure dialog is fully rendered + focusTimer.start(); + }); + } + } + + target: root.wrapper + } + + Timer { + id: focusTimer + + interval: 150 + onTriggered: { + root.forceActiveFocus(); + passwordContainer.forceActiveFocus(); + } + } + StyledRect { Layout.fillWidth: true Layout.preferredWidth: 400 implicitHeight: content.implicitHeight + Appearance.padding.large * 2 - radius: Appearance.rounding.normal color: Colours.tPalette.m3surfaceContainer visible: root.shouldBeVisible || root.isClosing opacity: root.shouldBeVisible && !root.isClosing ? 1 : 0 scale: root.shouldBeVisible && !root.isClosing ? 1 : 0.7 + Keys.onEscapePressed: root.closeDialog() Behavior on opacity { Anim {} @@ -165,8 +164,6 @@ ColumnLayout { } } - Keys.onEscapePressed: root.closeDialog() - ColumnLayout { id: content @@ -208,10 +205,11 @@ ColumnLayout { } Timer { + property int attempts: 0 + interval: 50 running: root.shouldBeVisible && (!root.network || !root.network.ssid) repeat: true - property int attempts: 0 onTriggered: { attempts++; // Keep trying to get network from Network component @@ -260,16 +258,15 @@ ColumnLayout { FocusScope { id: passwordContainer + property string passwordBuffer: "" + objectName: "passwordContainer" Layout.topMargin: Appearance.spacing.large Layout.fillWidth: true implicitHeight: Math.max(48, charList.implicitHeight + Appearance.padding.normal * 2) - focus: true activeFocusOnTab: true - property string passwordBuffer: "" - Keys.onPressed: event => { // Ensure we have focus when receiving keyboard input if (!activeFocus) { @@ -300,7 +297,6 @@ ColumnLayout { } Connections { - target: root function onShouldBeVisibleChanged(): void { if (root.shouldBeVisible) { // Use Timer for actual delay to ensure focus works correctly @@ -309,6 +305,8 @@ ColumnLayout { connectButton.hasError = false; } } + + target: root } Timer { @@ -549,10 +547,11 @@ ColumnLayout { Timer { id: connectionMonitor + property int repeatCount: 0 + interval: 1000 repeat: true triggeredOnStart: false - property int repeatCount: 0 onTriggered: { repeatCount++; @@ -589,12 +588,12 @@ ColumnLayout { } Connections { - target: Nmcli function onActiveChanged() { if (root.shouldBeVisible) { root.checkConnectionStatus(); } } + function onConnectionFailed(ssid: string) { if (root.shouldBeVisible && root.network && root.network.ssid === ssid && connectButton.connecting) { connectionMonitor.stop(); @@ -607,5 +606,7 @@ ColumnLayout { Nmcli.forgetNetwork(ssid); } } + + target: Nmcli } } diff --git a/modules/bar/popouts/Wrapper.qml b/modules/bar/popouts/Wrapper.qml index 05a1d3c9..40479f9a 100644 --- a/modules/bar/popouts/Wrapper.qml +++ b/modules/bar/popouts/Wrapper.qml @@ -124,12 +124,12 @@ Item { anchors.centerIn: parent sourceComponent: ControlCenter { - screen: root.screen - active: root.queuedMode - function close(): void { root.close(); } + + screen: root.screen + active: root.queuedMode } } diff --git a/modules/bar/popouts/kblayout/KbLayout.qml b/modules/bar/popouts/kblayout/KbLayout.qml index aba6e0cd..4e903e3e 100644 --- a/modules/bar/popouts/kblayout/KbLayout.qml +++ b/modules/bar/popouts/kblayout/KbLayout.qml @@ -89,11 +89,12 @@ ColumnLayout { delegate: Item { required property int layoutIndex required property string label + readonly property bool isDisabled: layoutIndex > 3 width: list.width height: Math.max(36, rowText.implicitHeight + Appearance.padding.small * 2) - - readonly property bool isDisabled: layoutIndex > 3 + ToolTip.visible: isDisabled && layer.containsMouse + ToolTip.text: "XKB limitation: maximum 4 layouts allowed" StateLayer { id: layer @@ -107,7 +108,6 @@ ColumnLayout { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter implicitHeight: parent.height - 4 - radius: Appearance.rounding.full enabled: !isDisabled } @@ -124,9 +124,6 @@ ColumnLayout { elide: Text.ElideRight opacity: isDisabled ? 0.4 : 1.0 } - - ToolTip.visible: isDisabled && layer.containsMouse - ToolTip.text: "XKB limitation: maximum 4 layouts allowed" } } @@ -167,12 +164,13 @@ ColumnLayout { } Connections { - target: kb function onActiveLabelChanged() { if (!activeRow.visible) return; popIn.restart(); } + + target: kb } SequentialAnimation { diff --git a/modules/controlcenter/ControlCenter.qml b/modules/controlcenter/ControlCenter.qml index 6478774f..637d127c 100644 --- a/modules/controlcenter/ControlCenter.qml +++ b/modules/controlcenter/ControlCenter.qml @@ -18,6 +18,7 @@ Item { property alias active: session.active property alias navExpanded: session.navExpanded + readonly property bool initialOpeningComplete: panes.initialOpeningComplete readonly property Session session: Session { id: session @@ -61,8 +62,6 @@ Item { color: Colours.tPalette.m3surfaceContainer CustomMouseArea { - anchors.fill: parent - function onWheel(event: WheelEvent): void { // Prevent tab switching during initial opening animation to avoid blank pages if (!panes.initialOpeningComplete) { @@ -74,6 +73,8 @@ Item { else if (event.angleDelta.y > 0) root.session.activeIndex = Math.max(root.session.activeIndex - 1, 0); } + + anchors.fill: parent } NavRail { @@ -96,6 +97,4 @@ Item { session: root.session } } - - readonly property bool initialOpeningComplete: panes.initialOpeningComplete } diff --git a/modules/controlcenter/NavRail.qml b/modules/controlcenter/NavRail.qml index 1de1e19c..b4eb4cd8 100644 --- a/modules/controlcenter/NavRail.qml +++ b/modules/controlcenter/NavRail.qml @@ -122,6 +122,7 @@ Item { NavItem { required property int index + Layout.topMargin: index === 0 ? Appearance.spacing.large * 2 : 0 icon: PaneRegistry.getByIndex(index).icon label: PaneRegistry.getByIndex(index).label diff --git a/modules/controlcenter/Panes.qml b/modules/controlcenter/Panes.qml index 5aacd89d..cd714706 100644 --- a/modules/controlcenter/Panes.qml +++ b/modules/controlcenter/Panes.qml @@ -37,23 +37,23 @@ ClippingRectangle { } Connections { - target: root.session - function onActiveIndexChanged(): void { root.focus = true; } + + target: root.session } ColumnLayout { id: layout + property bool animationComplete: true + property bool initialOpeningComplete: false + spacing: 0 y: -root.session.activeIndex * root.height clip: true - property bool animationComplete: true - property bool initialOpeningComplete: false - Timer { id: animationDelayTimer @@ -78,6 +78,7 @@ ClippingRectangle { Pane { required property int index + paneIndex: index componentPath: PaneRegistry.getByIndex(index).component } @@ -88,11 +89,12 @@ ClippingRectangle { } Connections { - target: root.session function onActiveIndexChanged(): void { layout.animationComplete = false; animationDelayTimer.restart(); } + + target: root.session } } @@ -158,20 +160,22 @@ ClippingRectangle { } Connections { - target: root.session function onActiveIndexChanged(): void { pane.updateActive(); } + + target: root.session } Connections { - target: layout function onInitialOpeningCompleteChanged(): void { pane.updateActive(); } function onAnimationCompleteChanged(): void { pane.updateActive(); } + + target: layout } } } diff --git a/modules/controlcenter/WindowFactory.qml b/modules/controlcenter/WindowFactory.qml index abcf5df1..068e970b 100644 --- a/modules/controlcenter/WindowFactory.qml +++ b/modules/controlcenter/WindowFactory.qml @@ -45,13 +45,13 @@ Singleton { ControlCenter { id: cc - anchors.fill: parent - screen: win.screen - floating: true - function close(): void { win.destroy(); } + + anchors.fill: parent + screen: win.screen + floating: true } Behavior on color { diff --git a/modules/controlcenter/appearance/AppearancePane.qml b/modules/controlcenter/appearance/AppearancePane.qml index 2b32ec03..2d22425e 100644 --- a/modules/controlcenter/appearance/AppearancePane.qml +++ b/modules/controlcenter/appearance/AppearancePane.qml @@ -152,11 +152,11 @@ Item { anchors.fill: parent leftContent: Component { - StyledFlickable { id: sidebarFlickable readonly property var rootPane: root + flickableDirection: Flickable.VerticalFlick contentHeight: sidebarLayout.height diff --git a/modules/controlcenter/appearance/sections/BackgroundSection.qml b/modules/controlcenter/appearance/sections/BackgroundSection.qml index 08186d03..7f528e99 100644 --- a/modules/controlcenter/appearance/sections/BackgroundSection.qml +++ b/modules/controlcenter/appearance/sections/BackgroundSection.qml @@ -79,19 +79,22 @@ CollapsibleSection { menuItems: [ MenuItem { + property string val: "top" + text: qsTr("Top") icon: "vertical_align_top" - property string val: "top" }, MenuItem { + property string val: "middle" + text: qsTr("Middle") icon: "vertical_align_center" - property string val: "middle" }, MenuItem { + property string val: "bottom" + text: qsTr("Bottom") icon: "vertical_align_bottom" - property string val: "bottom" } ] @@ -113,19 +116,22 @@ CollapsibleSection { menuItems: [ MenuItem { + property string val: "left" + text: qsTr("Left") icon: "align_horizontal_left" - property string val: "left" }, MenuItem { + property string val: "center" + text: qsTr("Center") icon: "align_horizontal_center" - property string val: "center" }, MenuItem { + property string val: "right" + text: qsTr("Right") icon: "align_horizontal_right" - property string val: "right" } ] diff --git a/modules/controlcenter/appearance/sections/FontsSection.qml b/modules/controlcenter/appearance/sections/FontsSection.qml index d3a2ce68..8c288608 100644 --- a/modules/controlcenter/appearance/sections/FontsSection.qml +++ b/modules/controlcenter/appearance/sections/FontsSection.qml @@ -48,10 +48,9 @@ CollapsibleSection { delegate: StyledRect { required property string modelData required property int index + readonly property bool isCurrent: modelData === rootPane.fontFamilySans 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 @@ -131,10 +130,9 @@ CollapsibleSection { delegate: StyledRect { required property string modelData required property int index + readonly property bool isCurrent: modelData === rootPane.fontFamilyMono 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 @@ -216,10 +214,9 @@ CollapsibleSection { delegate: StyledRect { required property string modelData required property int index + readonly property bool isCurrent: modelData === rootPane.fontFamilyMaterial 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 diff --git a/modules/controlcenter/audio/AudioPane.qml b/modules/controlcenter/audio/AudioPane.qml index deefc965..159c862e 100644 --- a/modules/controlcenter/audio/AudioPane.qml +++ b/modules/controlcenter/audio/AudioPane.qml @@ -23,7 +23,6 @@ Item { anchors.fill: parent leftContent: Component { - StyledFlickable { id: leftAudioFlickable @@ -280,12 +279,13 @@ Item { } Connections { - target: Audio function onVolumeChanged() { if (!outputVolumeInput.hasFocus) { outputVolumeInput.text = Math.round(Audio.volume * 100).toString(); } } + + target: Audio } onTextEdited: text => { @@ -397,12 +397,13 @@ Item { } Connections { - target: Audio function onSourceVolumeChanged() { if (!inputVolumeInput.hasFocus) { inputVolumeInput.text = Math.round(Audio.sourceVolume * 100).toString(); } } + + target: Audio } onTextEdited: text => { @@ -530,12 +531,13 @@ Item { } Connections { - target: modelData function onAudioChanged() { if (!streamVolumeInput.hasFocus && modelData?.audio) { streamVolumeInput.text = Math.round(modelData.audio.volume * 100).toString(); } } + + target: modelData } onTextEdited: text => { @@ -600,12 +602,13 @@ Item { } Connections { - target: modelData function onAudioChanged() { if (modelData?.audio) { value = modelData.audio.volume; } } + + target: modelData } } } diff --git a/modules/controlcenter/components/ConnectedButtonGroup.qml b/modules/controlcenter/components/ConnectedButtonGroup.qml index a85b4f3e..0f509877 100644 --- a/modules/controlcenter/components/ConnectedButtonGroup.qml +++ b/modules/controlcenter/components/ConnectedButtonGroup.qml @@ -58,11 +58,10 @@ StyledRect { required property int index required property var modelData - Layout.fillWidth: true - text: modelData.label - property bool _checked: false + Layout.fillWidth: true + text: modelData.label checked: _checked toggle: false type: TextButton.Tonal diff --git a/modules/controlcenter/components/SliderInput.qml b/modules/controlcenter/components/SliderInput.qml index 6b83a7a9..1aed5cbc 100644 --- a/modules/controlcenter/components/SliderInput.qml +++ b/modules/controlcenter/components/SliderInput.qml @@ -21,6 +21,9 @@ ColumnLayout { property int decimals: 1 // Number of decimal places to show (default: 1) property var formatValueFunction: null // Optional custom format function property var parseValueFunction: null // Optional custom parse function + property bool _initialized: false + + signal valueModified(real newValue) function formatValue(val: real): string { if (formatValueFunction) { @@ -49,10 +52,6 @@ ColumnLayout { return parseFloat(text); } - signal valueModified(real newValue) - - property bool _initialized: false - spacing: Appearance.spacing.small Component.onCompleted: { @@ -62,6 +61,14 @@ ColumnLayout { }); } + // Update input field when value changes externally (slider is already bound) + onValueChanged: { + // Only update if component is initialized to avoid issues during creation + if (root._initialized && !inputField.hasFocus) { + inputField.text = root.formatValue(root.value); + } + } + RowLayout { Layout.fillWidth: true spacing: Appearance.spacing.normal @@ -170,12 +177,4 @@ ColumnLayout { } } } - - // Update input field when value changes externally (slider is already bound) - onValueChanged: { - // Only update if component is initialized to avoid issues during creation - if (root._initialized && !inputField.hasFocus) { - inputField.text = root.formatValue(root.value); - } - } } diff --git a/modules/controlcenter/components/SplitPaneLayout.qml b/modules/controlcenter/components/SplitPaneLayout.qml index bf513e56..5c1a8be6 100644 --- a/modules/controlcenter/components/SplitPaneLayout.qml +++ b/modules/controlcenter/components/SplitPaneLayout.qml @@ -10,19 +10,17 @@ import QtQuick.Layouts RowLayout { id: root - spacing: 0 - property Component leftContent: null property Component rightContent: null - property real leftWidthRatio: 0.4 property int leftMinimumWidth: 420 property var leftLoaderProperties: ({}) property var rightLoaderProperties: ({}) - property alias leftLoader: leftLoader property alias rightLoader: rightLoader + spacing: 0 + Item { id: leftPane diff --git a/modules/controlcenter/components/WallpaperGrid.qml b/modules/controlcenter/components/WallpaperGrid.qml index 500dd821..588d51d1 100644 --- a/modules/controlcenter/components/WallpaperGrid.qml +++ b/modules/controlcenter/components/WallpaperGrid.qml @@ -32,14 +32,13 @@ GridView { delegate: Item { required property var modelData required property int index - - width: root.cellWidth - height: root.cellHeight - readonly property bool isCurrent: modelData && modelData.path === Wallpapers.actualCurrent readonly property real itemMargin: Appearance.spacing.normal / 2 readonly property real itemRadius: Appearance.rounding.normal + width: root.cellWidth + height: root.cellHeight + StateLayer { function onClicked(): void { Wallpapers.setWallpaper(modelData.path); @@ -117,6 +116,7 @@ GridView { id: fallbackTimer property bool triggered: false + interval: 800 running: cachingImage.status === Image.Loading || cachingImage.status === Image.Null onTriggered: triggered = true diff --git a/modules/controlcenter/launcher/LauncherPane.qml b/modules/controlcenter/launcher/LauncherPane.qml index 5ce5139d..6de34469 100644 --- a/modules/controlcenter/launcher/LauncherPane.qml +++ b/modules/controlcenter/launcher/LauncherPane.qml @@ -108,12 +108,21 @@ Item { updateToggleState(); } + onSearchTextChanged: { + updateFilteredApps(); + } + + Component.onCompleted: { + updateFilteredApps(); + } + Connections { - target: root.session.launcher function onActiveChanged() { root.selectedApp = root.session.launcher.active; updateToggleState(); } + + target: root.session.launcher } AppDb { @@ -124,26 +133,18 @@ Item { entries: DesktopEntries.applications.values } - onSearchTextChanged: { - updateFilteredApps(); - } - - Component.onCompleted: { - updateFilteredApps(); - } - Connections { - target: allAppsDb function onAppsChanged() { updateFilteredApps(); } + + target: allAppsDb } SplitPaneLayout { anchors.fill: parent leftContent: Component { - ColumnLayout { id: leftLauncherLayout @@ -358,9 +359,10 @@ Item { } Loader { - Layout.alignment: Qt.AlignVCenter readonly property bool isHidden: modelData ? Strings.testRegexList(Config.launcher.hiddenApps, modelData.id) : false readonly property bool isFav: modelData ? Strings.testRegexList(Config.launcher.favouriteApps, modelData.id) : false + + Layout.alignment: Qt.AlignVCenter asynchronous: true active: isHidden || isFav @@ -413,6 +415,22 @@ Item { nextComponent = targetComponent; } + onPaneChanged: { + nextComponent = getComponentForPane(); + paneId = pane ? (pane.id || pane.entry?.id || "") : ""; + } + + onDisplayedAppChanged: { + if (displayedApp) { + const appId = displayedApp.id || displayedApp.entry?.id; + root.hideFromLauncherChecked = Config.launcher.hiddenApps && Config.launcher.hiddenApps.length > 0 && Strings.testRegexList(Config.launcher.hiddenApps, appId); + root.favouriteChecked = Config.launcher.favouriteApps && Config.launcher.favouriteApps.length > 0 && Strings.testRegexList(Config.launcher.favouriteApps, appId); + } else { + root.hideFromLauncherChecked = false; + root.favouriteChecked = false; + } + } + Loader { id: rightLauncherLoader @@ -463,22 +481,6 @@ Item { ] } } - - onPaneChanged: { - nextComponent = getComponentForPane(); - paneId = pane ? (pane.id || pane.entry?.id || "") : ""; - } - - onDisplayedAppChanged: { - if (displayedApp) { - const appId = displayedApp.id || displayedApp.entry?.id; - root.hideFromLauncherChecked = Config.launcher.hiddenApps && Config.launcher.hiddenApps.length > 0 && Strings.testRegexList(Config.launcher.hiddenApps, appId); - root.favouriteChecked = Config.launcher.favouriteApps && Config.launcher.favouriteApps.length > 0 && Strings.testRegexList(Config.launcher.favouriteApps, appId); - } else { - root.hideFromLauncherChecked = false; - root.favouriteChecked = false; - } - } } } } diff --git a/modules/controlcenter/network/NetworkingPane.qml b/modules/controlcenter/network/NetworkingPane.qml index 78d5fc93..0a6b20e2 100644 --- a/modules/controlcenter/network/NetworkingPane.qml +++ b/modules/controlcenter/network/NetworkingPane.qml @@ -199,9 +199,6 @@ Item { } Connections { - target: root.session && root.session.vpn ? root.session.vpn : null - enabled: target !== null - function onActiveChanged() { // Clear others when VPN is selected if (root.session && root.session.vpn && root.session.vpn.active) { @@ -212,12 +209,12 @@ Item { } rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); } + + target: root.session && root.session.vpn ? root.session.vpn : null + enabled: target !== null } Connections { - target: root.session && root.session.ethernet ? root.session.ethernet : null - enabled: target !== null - function onActiveChanged() { // Clear others when ethernet is selected if (root.session && root.session.ethernet && root.session.ethernet.active) { @@ -228,12 +225,12 @@ Item { } rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); } + + target: root.session && root.session.ethernet ? root.session.ethernet : null + enabled: target !== null } Connections { - target: root.session && root.session.network ? root.session.network : null - enabled: target !== null - function onActiveChanged() { // Clear others when wireless is selected if (root.session && root.session.network && root.session.network.active) { @@ -244,6 +241,9 @@ Item { } rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); } + + target: root.session && root.session.network ? root.session.network : null + enabled: target !== null } Loader { diff --git a/modules/controlcenter/network/VpnList.qml b/modules/controlcenter/network/VpnList.qml index 9c336674..e8b49d38 100644 --- a/modules/controlcenter/network/VpnList.qml +++ b/modules/controlcenter/network/VpnList.qml @@ -21,7 +21,6 @@ ColumnLayout { spacing: Appearance.spacing.normal Connections { - target: VPN function onConnectedChanged() { if (!VPN.connected && root.pendingSwitchIndex >= 0) { const targetIndex = root.pendingSwitchIndex; @@ -50,6 +49,8 @@ ColumnLayout { }); } } + + target: VPN } TextButton { @@ -367,36 +368,6 @@ ColumnLayout { currentState = "selection"; } - SequentialAnimation { - id: transitionToForm - - ParallelAnimation { - Anim { - target: selectionContent - property: "opacity" - to: 0 - duration: Appearance.anim.durations.small - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - - ScriptAction { - script: { - vpnDialog.currentState = "form"; - } - } - - ParallelAnimation { - Anim { - target: formContent - property: "opacity" - to: 1 - duration: Appearance.anim.durations.small - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - } - background: StyledRect { color: Colours.palette.m3surfaceContainerHigh radius: Appearance.rounding.large @@ -685,5 +656,35 @@ ColumnLayout { } } } + + SequentialAnimation { + id: transitionToForm + + ParallelAnimation { + Anim { + target: selectionContent + property: "opacity" + to: 0 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + ScriptAction { + script: { + vpnDialog.currentState = "form"; + } + } + + ParallelAnimation { + Anim { + target: formContent + property: "opacity" + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } } } diff --git a/modules/controlcenter/network/WirelessDetails.qml b/modules/controlcenter/network/WirelessDetails.qml index 29b2f627..beaaff3f 100644 --- a/modules/controlcenter/network/WirelessDetails.qml +++ b/modules/controlcenter/network/WirelessDetails.qml @@ -19,67 +19,12 @@ DeviceDetails { required property Session session readonly property var network: root.session.network.active - device: network - - Component.onCompleted: { - updateDeviceDetails(); - checkSavedProfile(); - } - - onNetworkChanged: { - connectionUpdateTimer.stop(); - if (network && network.ssid) { - connectionUpdateTimer.start(); - } - updateDeviceDetails(); - checkSavedProfile(); - } - function checkSavedProfile(): void { if (network && network.ssid) { Nmcli.loadSavedConnections(() => {}); } } - Connections { - target: Nmcli - function onActiveChanged() { - updateDeviceDetails(); - } - function onWirelessDeviceDetailsChanged() { - if (network && network.ssid) { - const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); - if (isActive && Nmcli.wirelessDeviceDetails && Nmcli.wirelessDeviceDetails !== null) { - connectionUpdateTimer.stop(); - } - } - } - } - - Timer { - id: connectionUpdateTimer - - interval: 500 - repeat: true - running: network && network.ssid - onTriggered: { - if (network) { - const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); - if (isActive) { - if (!Nmcli.wirelessDeviceDetails || Nmcli.wirelessDeviceDetails === null) { - Nmcli.getWirelessDeviceDetails("", () => {}); - } else { - connectionUpdateTimer.stop(); - } - } else { - if (Nmcli.wirelessDeviceDetails !== null) { - Nmcli.wirelessDeviceDetails = null; - } - } - } - } - } - function updateDeviceDetails(): void { if (network && network.ssid) { const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); @@ -93,6 +38,22 @@ DeviceDetails { } } + device: network + + Component.onCompleted: { + updateDeviceDetails(); + checkSavedProfile(); + } + + onNetworkChanged: { + connectionUpdateTimer.stop(); + if (network && network.ssid) { + connectionUpdateTimer.start(); + } + updateDeviceDetails(); + checkSavedProfile(); + } + headerComponent: Component { ConnectionHeader { icon: root.network?.isSecure ? "lock" : "wifi" @@ -209,4 +170,44 @@ DeviceDetails { } } ] + + Connections { + function onActiveChanged() { + updateDeviceDetails(); + } + function onWirelessDeviceDetailsChanged() { + if (network && network.ssid) { + const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); + if (isActive && Nmcli.wirelessDeviceDetails && Nmcli.wirelessDeviceDetails !== null) { + connectionUpdateTimer.stop(); + } + } + } + + target: Nmcli + } + + Timer { + id: connectionUpdateTimer + + interval: 500 + repeat: true + running: network && network.ssid + onTriggered: { + if (network) { + const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); + if (isActive) { + if (!Nmcli.wirelessDeviceDetails || Nmcli.wirelessDeviceDetails === null) { + Nmcli.getWirelessDeviceDetails("", () => {}); + } else { + connectionUpdateTimer.stop(); + } + } else { + if (Nmcli.wirelessDeviceDetails !== null) { + Nmcli.wirelessDeviceDetails = null; + } + } + } + } + } } diff --git a/modules/controlcenter/network/WirelessList.qml b/modules/controlcenter/network/WirelessList.qml index 57a155fd..1713022e 100644 --- a/modules/controlcenter/network/WirelessList.qml +++ b/modules/controlcenter/network/WirelessList.qml @@ -19,6 +19,12 @@ DeviceList { required property Session session + function checkSavedProfileForNetwork(ssid: string): void { + if (ssid && ssid.length > 0) { + Nmcli.loadSavedConnections(() => {}); + } + } + title: qsTr("Networks (%1)").arg(Nmcli.networks.length) description: qsTr("All available WiFi networks") activeItem: session.network.active @@ -219,10 +225,4 @@ DeviceList { checkSavedProfileForNetwork(item.ssid); } } - - function checkSavedProfileForNetwork(ssid: string): void { - if (ssid && ssid.length > 0) { - Nmcli.loadSavedConnections(() => {}); - } - } } diff --git a/modules/controlcenter/network/WirelessPasswordDialog.qml b/modules/controlcenter/network/WirelessPasswordDialog.qml index 09d6a826..6db01bc0 100644 --- a/modules/controlcenter/network/WirelessPasswordDialog.qml +++ b/modules/controlcenter/network/WirelessPasswordDialog.qml @@ -192,10 +192,11 @@ Item { Item { id: passwordContainer + property string passwordBuffer: "" + Layout.topMargin: Appearance.spacing.large Layout.fillWidth: true implicitHeight: Math.max(48, charList.implicitHeight + Appearance.padding.normal * 2) - focus: true Keys.onPressed: event => { if (!activeFocus) { @@ -224,10 +225,7 @@ Item { } } - property string passwordBuffer: "" - Connections { - target: root.session.network function onShowPasswordDialogChanged(): void { if (root.session.network.showPasswordDialog) { Qt.callLater(() => { @@ -237,10 +235,11 @@ Item { }); } } + + target: root.session.network } Connections { - target: root function onVisibleChanged(): void { if (root.visible) { Qt.callLater(() => { @@ -248,6 +247,8 @@ Item { }); } } + + target: root } StyledRect { @@ -460,11 +461,11 @@ Item { Timer { id: connectionMonitor + property int repeatCount: 0 + interval: 1000 repeat: true triggeredOnStart: false - property int repeatCount: 0 - onTriggered: { repeatCount++; checkConnectionStatus(); @@ -495,7 +496,6 @@ Item { } Connections { - target: Nmcli function onActiveChanged() { if (root.visible) { checkConnectionStatus(); @@ -512,5 +512,7 @@ Item { Nmcli.forgetNetwork(ssid); } } + + target: Nmcli } } diff --git a/modules/dashboard/LyricMenu.qml b/modules/dashboard/LyricMenu.qml index 868eb8d3..0dc923cc 100644 --- a/modules/dashboard/LyricMenu.qml +++ b/modules/dashboard/LyricMenu.qml @@ -92,18 +92,17 @@ StyledRect { delegate: Item { id: delegateRoot - width: ListView.view.width * 0.98 - height: 70 - anchors.horizontalCenter: parent?.horizontalCenter - required property real id required property string title required property string artist - property bool hovered: false property bool pressed: false + width: ListView.view.width * 0.98 + height: 70 + anchors.horizontalCenter: parent?.horizontalCenter scale: hovered ? 1.02 : 1.0 + Behavior on scale { NumberAnimation { duration: Appearance.anim.durations.small @@ -158,6 +157,7 @@ StyledRect { radius: 2 anchors.verticalCenter: parent.verticalCenter color: LyricsService.currentSongId === delegateRoot.id ? Colours.palette.m3primary : "transparent" + Behavior on color { ColorAnimation { duration: Appearance.anim.durations.small @@ -177,6 +177,7 @@ StyledRect { color: delegateRoot.hovered ? Colours.palette.m3primary : Colours.palette.m3onSurface width: parent.width elide: Text.ElideRight + Behavior on color { ColorAnimation { duration: Appearance.anim.durations.small @@ -288,21 +289,6 @@ StyledRect { font.pointSize: Appearance.font.size.normal selectByMouse: true text: (LyricsService.offset >= 0 ? "+" : "") + LyricsService.offset.toFixed(1) + "s" - - Binding { - target: offsetInput - property: "text" - value: (LyricsService.offset >= 0 ? "+" : "") + LyricsService.offset.toFixed(1) + "s" - when: !offsetInput.activeFocus - } - - Connections { - target: LyricsService - function onCurrentRequestIdChanged() { - offsetInput.focus = false; - } - } - onEditingFinished: { let cleaned = offsetInput.text.replace(/[+s]/g, "").trim(); let val = parseFloat(cleaned); @@ -313,6 +299,21 @@ StyledRect { offsetInput.text = (LyricsService.offset >= 0 ? "+" : "") + LyricsService.offset.toFixed(1) + "s"; } } + + Binding { + target: offsetInput + property: "text" + value: (LyricsService.offset >= 0 ? "+" : "") + LyricsService.offset.toFixed(1) + "s" + when: !offsetInput.activeFocus + } + + Connections { + function onCurrentRequestIdChanged() { + offsetInput.focus = false; + } + + target: LyricsService + } } IconButton { diff --git a/modules/dashboard/LyricsView.qml b/modules/dashboard/LyricsView.qml index 38972402..29fd9645 100644 --- a/modules/dashboard/LyricsView.qml +++ b/modules/dashboard/LyricsView.qml @@ -14,55 +14,40 @@ StyledListView { clip: true model: LyricsService.model currentIndex: LyricsService.currentIndex - visible: lyricsActuallyVisible || hideTimer.running - - onLyricsActuallyVisibleChanged: { - if (!lyricsActuallyVisible) - hideTimer.restart(); - } - - Timer { - id: hideTimer - - interval: 300 // long enough to bridge the track switch gap - running: false - repeat: false - } - preferredHighlightBegin: height / 2 - 30 preferredHighlightEnd: height / 2 + 30 highlightRangeMode: ListView.ApplyRange highlightFollowsCurrentItem: true highlightMoveDuration: LyricsService.isManualSeeking ? 0 : Appearance.anim.durations.normal - layer.enabled: true layer.effect: ShaderEffect { required property Item source property real fadeMargin: 0.5 + fragmentShader: Quickshell.shellPath("assets/shaders/fade.frag.qsb") } - + onLyricsActuallyVisibleChanged: { + if (!lyricsActuallyVisible) + hideTimer.restart(); + } onModelChanged: { if (model && model.count > 0) { Qt.callLater(() => positionViewAtIndex(currentIndex, ListView.Center)); } } - delegate: Item { id: delegateRoot - width: ListView.view.width - required property string lyricLine required property real time required property int index - readonly property bool hasContent: lyricLine && lyricLine.trim().length > 0 - height: hasContent ? (lyricText.contentHeight + Appearance.spacing.large) : 0 - property bool isCurrent: ListView.isCurrentItem + width: ListView.view.width + height: hasContent ? (lyricText.contentHeight + Appearance.spacing.large) : 0 + MultiEffect { id: effect @@ -103,6 +88,7 @@ StyledListView { color: delegateRoot.isCurrent ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant font.bold: delegateRoot.isCurrent scale: delegateRoot.isCurrent ? 1.15 : 1.0 + Behavior on color { CAnim { duration: Appearance.anim.durations.small @@ -115,4 +101,12 @@ StyledListView { } } } + + Timer { + id: hideTimer + + interval: 300 // long enough to bridge the track switch gap + running: false + repeat: false + } } diff --git a/modules/dashboard/Media.qml b/modules/dashboard/Media.qml index 69e21524..25511e8c 100644 --- a/modules/dashboard/Media.qml +++ b/modules/dashboard/Media.qml @@ -86,10 +86,11 @@ Item { } Connections { - target: lyricsHideDelay function onTriggered() { root.lyricsShowingDebounced = false; } + + target: lyricsHideDelay } ServiceRef { @@ -327,9 +328,6 @@ Item { } CustomMouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - function onWheel(event: WheelEvent) { const active = Players.active; if (!active?.canSeek || !active?.positionSupported) @@ -341,6 +339,9 @@ Item { active.position = Math.max(0, Math.min(active.length, active.position + delta)); }); } + + anchors.fill: parent + acceptedButtons: Qt.NoButton } } @@ -380,6 +381,7 @@ Item { visible: lyricMenu.height === 0 || opacity > 0 opacity: lyricMenu.height === 0 ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: Appearance.anim.durations.normal @@ -421,6 +423,7 @@ Item { visible: root.lyricMenuOpen || height > 0 height: root.lyricMenuOpen ? implicitHeight : 0 clip: true + Behavior on height { NumberAnimation { duration: Appearance.anim.durations.normal diff --git a/modules/dashboard/Performance.qml b/modules/dashboard/Performance.qml index 339c731f..2551bc95 100644 --- a/modules/dashboard/Performance.qml +++ b/modules/dashboard/Performance.qml @@ -695,12 +695,12 @@ Item { historyLength: NetworkUsage.historyLength Connections { - target: NetworkUsage.downloadBuffer - function onValuesChanged(): void { sparkline.targetMax = Math.max(NetworkUsage.downloadBuffer.maximum, NetworkUsage.uploadBuffer.maximum, 1024); slideAnim.restart(); } + + target: NetworkUsage.downloadBuffer } NumberAnimation { diff --git a/modules/dashboard/Weather.qml b/modules/dashboard/Weather.qml index 3981633a..d15d1ed6 100644 --- a/modules/dashboard/Weather.qml +++ b/modules/dashboard/Weather.qml @@ -7,11 +7,10 @@ import QtQuick.Layouts Item { id: root - implicitWidth: layout.implicitWidth > 800 ? layout.implicitWidth : 840 - implicitHeight: layout.implicitHeight - readonly property var today: Weather.forecast && Weather.forecast.length > 0 ? Weather.forecast[0] : null + implicitWidth: layout.implicitWidth > 800 ? layout.implicitWidth : 840 + implicitHeight: layout.implicitHeight Component.onCompleted: Weather.reload() ColumnLayout { diff --git a/modules/dashboard/dash/Media.qml b/modules/dashboard/dash/Media.qml index 2891bd55..cb764dc0 100644 --- a/modules/dashboard/dash/Media.qml +++ b/modules/dashboard/dash/Media.qml @@ -174,30 +174,30 @@ Item { spacing: Appearance.spacing.small Control { - icon: "skip_previous" - canUse: Players.active?.canGoPrevious ?? false - function onClicked(): void { Players.active?.previous(); } + + icon: "skip_previous" + canUse: Players.active?.canGoPrevious ?? false } Control { - icon: Players.active?.isPlaying ? "pause" : "play_arrow" - canUse: Players.active?.canTogglePlaying ?? false - function onClicked(): void { Players.active?.togglePlaying(); } + + icon: Players.active?.isPlaying ? "pause" : "play_arrow" + canUse: Players.active?.canTogglePlaying ?? false } Control { - icon: "skip_next" - canUse: Players.active?.canGoNext ?? false - function onClicked(): void { Players.active?.next(); } + + icon: "skip_next" + canUse: Players.active?.canGoNext ?? false } } @@ -224,6 +224,7 @@ Item { required property string icon required property bool canUse + function onClicked(): void { } diff --git a/modules/drawers/Interactions.qml b/modules/drawers/Interactions.qml index 10807fce..d017decb 100644 --- a/modules/drawers/Interactions.qml +++ b/modules/drawers/Interactions.qml @@ -209,8 +209,6 @@ CustomMouseArea { // Monitor individual visibility changes Connections { - target: root.visibilities - function onLauncherChanged() { // If launcher is hidden, clear shortcut flags for dashboard and OSD if (!root.visibilities.launcher) { @@ -270,5 +268,7 @@ CustomMouseArea { root.utilitiesShortcutActive = false; } } + + target: root.visibilities } } diff --git a/modules/launcher/Content.qml b/modules/launcher/Content.qml index c0859769..55982d31 100644 --- a/modules/launcher/Content.qml +++ b/modules/launcher/Content.qml @@ -130,8 +130,6 @@ Item { Component.onCompleted: forceActiveFocus() Connections { - target: root.visibilities - function onLauncherChanged(): void { if (!root.visibilities.launcher) search.text = ""; @@ -141,6 +139,8 @@ Item { if (!root.visibilities.session) search.forceActiveFocus(); } + + target: root.visibilities } } diff --git a/modules/launcher/Wrapper.qml b/modules/launcher/Wrapper.qml index d62d726a..749b41c2 100644 --- a/modules/launcher/Wrapper.qml +++ b/modules/launcher/Wrapper.qml @@ -69,8 +69,6 @@ Item { } Connections { - target: Config.launcher - function onEnabledChanged(): void { timer.start(); } @@ -78,15 +76,17 @@ Item { function onMaxShownChanged(): void { timer.start(); } + + target: Config.launcher } Connections { - target: DesktopEntries.applications - function onValuesChanged(): void { if (DesktopEntries.applications.values.length < Config.launcher.maxShown) timer.start(); } + + target: DesktopEntries.applications } Timer { diff --git a/modules/lock/Center.qml b/modules/lock/Center.qml index 5d4dec85..24fb8d4d 100644 --- a/modules/lock/Center.qml +++ b/modules/lock/Center.qml @@ -357,8 +357,6 @@ ColumnLayout { } Connections { - target: root.lock.pam - function onFlashMsg(): void { exitAnim.stop(); if (message.scale < 1) @@ -366,6 +364,8 @@ ColumnLayout { else flashAnim.restart(); } + + target: root.lock.pam } Anim { diff --git a/modules/lock/InputField.qml b/modules/lock/InputField.qml index 358093f3..885487b9 100644 --- a/modules/lock/InputField.qml +++ b/modules/lock/InputField.qml @@ -20,8 +20,6 @@ Item { clip: true Connections { - target: root.pam - function onBufferChanged(): void { if (root.pam.buffer.length > root.buffer.length) { charList.bindImWidth(); @@ -32,6 +30,8 @@ Item { root.buffer = root.pam.buffer; } + + target: root.pam } StyledText { diff --git a/modules/lock/Lock.qml b/modules/lock/Lock.qml index 6fd5277f..a4795016 100644 --- a/modules/lock/Lock.qml +++ b/modules/lock/Lock.qml @@ -38,8 +38,6 @@ Scope { } IpcHandler { - target: "lock" - function lock(): void { lock.locked = true; } @@ -51,5 +49,7 @@ Scope { function isLocked(): bool { return lock.locked; } + + target: "lock" } } diff --git a/modules/lock/LockSurface.qml b/modules/lock/LockSurface.qml index 279c5513..54fa1b94 100644 --- a/modules/lock/LockSurface.qml +++ b/modules/lock/LockSurface.qml @@ -18,11 +18,11 @@ WlSessionLockSurface { color: "transparent" Connections { - target: root.lock - function onUnlock(): void { unlockAnim.start(); } + + target: root.lock } SequentialAnimation { diff --git a/modules/lock/Media.qml b/modules/lock/Media.qml index 07ec8c5b..d06d374a 100644 --- a/modules/lock/Media.qml +++ b/modules/lock/Media.qml @@ -110,34 +110,34 @@ Item { spacing: Appearance.spacing.large PlayerControl { - icon: "skip_previous" - function onClicked(): void { if (Players.active?.canGoPrevious) Players.active.previous(); } + + icon: "skip_previous" } PlayerControl { + function onClicked(): void { + if (Players.active?.canTogglePlaying) + Players.active.togglePlaying(); + } + animate: true icon: active ? "pause" : "play_arrow" colour: "Primary" level: active ? 2 : 1 active: Players.active?.isPlaying ?? false - - function onClicked(): void { - if (Players.active?.canTogglePlaying) - Players.active.togglePlaying(); - } } PlayerControl { - icon: "skip_next" - function onClicked(): void { if (Players.active?.canGoNext) Players.active.next(); } + + icon: "skip_next" } } } diff --git a/modules/lock/Pam.qml b/modules/lock/Pam.qml index 0186c2f8..31f9fdfa 100644 --- a/modules/lock/Pam.qml +++ b/modules/lock/Pam.qml @@ -166,8 +166,6 @@ Scope { } Connections { - target: root.lock - function onSecureChanged(): void { if (root.lock.secure) { availProc.running = true; @@ -181,13 +179,15 @@ Scope { function onUnlock(): void { fprint.abort(); } + + target: root.lock } Connections { - target: Config.lock - function onEnableFprintChanged(): void { fprint.checkAvail(); } + + target: Config.lock } } diff --git a/modules/notifications/Notification.qml b/modules/notifications/Notification.qml index a1bf97d8..e3ed784c 100644 --- a/modules/notifications/Notification.qml +++ b/modules/notifications/Notification.qml @@ -460,6 +460,7 @@ StyledRect { Action { modelData: QtObject { readonly property string text: qsTr("Close") + function invoke(): void { root.modelData.close(); } diff --git a/modules/osd/Content.qml b/modules/osd/Content.qml index 6776bb8f..53c50d7f 100644 --- a/modules/osd/Content.qml +++ b/modules/osd/Content.qml @@ -31,9 +31,6 @@ Item { // Speaker volume CustomMouseArea { - implicitWidth: Config.osd.sizes.sliderWidth - implicitHeight: Config.osd.sizes.sliderHeight - function onWheel(event: WheelEvent) { if (event.angleDelta.y > 0) Audio.incrementVolume(); @@ -41,6 +38,9 @@ Item { Audio.decrementVolume(); } + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + FilledSlider { anchors.fill: parent @@ -56,9 +56,6 @@ Item { shouldBeActive: Config.osd.enableMicrophone && (!Config.osd.enableBrightness || !root.visibilities.session) sourceComponent: CustomMouseArea { - implicitWidth: Config.osd.sizes.sliderWidth - implicitHeight: Config.osd.sizes.sliderHeight - function onWheel(event: WheelEvent) { if (event.angleDelta.y > 0) Audio.incrementSourceVolume(); @@ -66,6 +63,9 @@ Item { Audio.decrementSourceVolume(); } + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + FilledSlider { anchors.fill: parent @@ -82,9 +82,6 @@ Item { shouldBeActive: Config.osd.enableBrightness sourceComponent: CustomMouseArea { - implicitWidth: Config.osd.sizes.sliderWidth - implicitHeight: Config.osd.sizes.sliderHeight - function onWheel(event: WheelEvent) { const monitor = root.monitor; if (!monitor) @@ -95,6 +92,9 @@ Item { monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); } + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + FilledSlider { anchors.fill: parent diff --git a/modules/osd/Wrapper.qml b/modules/osd/Wrapper.qml index 2519609d..e674d638 100644 --- a/modules/osd/Wrapper.qml +++ b/modules/osd/Wrapper.qml @@ -71,8 +71,6 @@ Item { ] Connections { - target: Audio - function onMutedChanged(): void { root.show(); root.muted = Audio.muted; @@ -92,15 +90,17 @@ Item { root.show(); root.sourceVolume = Audio.sourceVolume; } + + target: Audio } Connections { - target: root.monitor - function onBrightnessChanged(): void { root.show(); root.brightness = root.monitor?.brightness ?? 0; } + + target: root.monitor } Timer { diff --git a/modules/session/Content.qml b/modules/session/Content.qml index 06e6c85f..726d24b3 100644 --- a/modules/session/Content.qml +++ b/modules/session/Content.qml @@ -26,12 +26,12 @@ Column { Component.onCompleted: forceActiveFocus() Connections { - target: root.visibilities - function onLauncherChanged(): void { if (!root.visibilities.launcher) logout.forceActiveFocus(); } + + target: root.visibilities } } diff --git a/modules/windowinfo/Buttons.qml b/modules/windowinfo/Buttons.qml index 7854045c..fe4c621a 100644 --- a/modules/windowinfo/Buttons.qml +++ b/modules/windowinfo/Buttons.qml @@ -81,14 +81,14 @@ ColumnLayout { readonly property int wsId: Math.floor((Hypr.activeWsId - 1) / 10) * 10 + index + 1 readonly property bool isCurrent: root.client?.workspace.id === wsId + function onClicked(): void { + Hypr.dispatch(`movetoworkspace ${wsId},address:0x${root.client?.address}`); + } + color: isCurrent ? Colours.tPalette.m3surfaceContainerHighest : Colours.palette.m3tertiaryContainer onColor: isCurrent ? Colours.palette.m3onSurface : Colours.palette.m3onTertiaryContainer text: wsId disabled: isCurrent - - function onClicked(): void { - Hypr.dispatch(`movetoworkspace ${wsId},address:0x${root.client?.address}`); - } } } } @@ -107,13 +107,13 @@ ColumnLayout { spacing: root.client?.lastIpcObject.floating ? Appearance.spacing.normal : Appearance.spacing.small Button { - color: Colours.palette.m3secondaryContainer - onColor: Colours.palette.m3onSecondaryContainer - text: root.client?.lastIpcObject.floating ? qsTr("Tile") : qsTr("Float") - function onClicked(): void { Hypr.dispatch(`togglefloating address:0x${root.client?.address}`); } + + color: Colours.palette.m3secondaryContainer + onColor: Colours.palette.m3onSecondaryContainer + text: root.client?.lastIpcObject.floating ? qsTr("Tile") : qsTr("Float") } Loader { @@ -124,24 +124,24 @@ ColumnLayout { Layout.rightMargin: active ? 0 : -parent.spacing sourceComponent: Button { - color: Colours.palette.m3secondaryContainer - onColor: Colours.palette.m3onSecondaryContainer - text: root.client?.lastIpcObject.pinned ? qsTr("Unpin") : qsTr("Pin") - function onClicked(): void { Hypr.dispatch(`pin address:0x${root.client?.address}`); } + + color: Colours.palette.m3secondaryContainer + onColor: Colours.palette.m3onSecondaryContainer + text: root.client?.lastIpcObject.pinned ? qsTr("Unpin") : qsTr("Pin") } } Button { - color: Colours.palette.m3errorContainer - onColor: Colours.palette.m3onErrorContainer - text: qsTr("Kill") - function onClicked(): void { Hypr.dispatch(`killwindow address:0x${root.client?.address}`); } + + color: Colours.palette.m3errorContainer + onColor: Colours.palette.m3onErrorContainer + text: qsTr("Kill") } } diff --git a/services/Audio.qml b/services/Audio.qml index 14d0a4e8..d3e73ab6 100644 --- a/services/Audio.qml +++ b/services/Audio.qml @@ -125,8 +125,6 @@ Singleton { } Connections { - target: Pipewire.nodes - function onValuesChanged(): void { const newSinks = []; const newSources = []; @@ -147,6 +145,8 @@ Singleton { root.sources = newSources; root.streams = newStreams; } + + target: Pipewire.nodes } PwObjectTracker { diff --git a/services/Brightness.qml b/services/Brightness.qml index 56782404..907c0b09 100644 --- a/services/Brightness.qml +++ b/services/Brightness.qml @@ -105,8 +105,6 @@ Singleton { } IpcHandler { - target: "brightness" - function get(): real { return getFor("active"); } @@ -155,6 +153,8 @@ Singleton { return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`; } + + target: "brightness" } component Monitor: QtObject { diff --git a/services/GameMode.qml b/services/GameMode.qml index 83770b79..6e9d9604 100644 --- a/services/GameMode.qml +++ b/services/GameMode.qml @@ -46,17 +46,15 @@ Singleton { } Connections { - target: Hypr - function onConfigReloaded(): void { if (props.enabled) root.setDynamicConfs(); } + + target: Hypr } IpcHandler { - target: "gameMode" - function isEnabled(): bool { return props.enabled; } @@ -72,5 +70,7 @@ Singleton { function disable(): void { props.enabled = false; } + + target: "gameMode" } } diff --git a/services/Hypr.qml b/services/Hypr.qml index c703f704..52e3d28f 100644 --- a/services/Hypr.qml +++ b/services/Hypr.qml @@ -120,8 +120,6 @@ Singleton { } Connections { - target: Hyprland - function onRawEvent(event: HyprlandEvent): void { const n = event.name; if (n.endsWith("v2")) @@ -144,11 +142,11 @@ Singleton { Hyprland.refreshToplevels(); } } + + target: Hyprland } Connections { - target: root.focusedMonitor - function onLastIpcObjectChanged(): void { const specialName = root.focusedMonitor.lastIpcObject.specialWorkspace.name; @@ -156,6 +154,8 @@ Singleton { root.lastSpecialWorkspace = specialName; } } + + target: root.focusedMonitor } FileView { @@ -192,8 +192,6 @@ Singleton { } IpcHandler { - target: "hypr" - function refreshDevices(): void { extras.refreshDevices(); } @@ -205,6 +203,8 @@ Singleton { function listSpecialWorkspaces(): string { return root.workspaces.values.filter(w => w.name.startsWith("special:") && w.lastIpcObject.windows > 0).map(w => w.name).join("\n"); } + + target: "hypr" } CustomShortcut { diff --git a/services/IdleInhibitor.qml b/services/IdleInhibitor.qml index 29409abc..9f556b3a 100644 --- a/services/IdleInhibitor.qml +++ b/services/IdleInhibitor.qml @@ -35,8 +35,6 @@ Singleton { } IpcHandler { - target: "idleInhibitor" - function isEnabled(): bool { return props.enabled; } @@ -52,5 +50,7 @@ Singleton { function disable(): void { props.enabled = false; } + + target: "idleInhibitor" } } diff --git a/services/LyricsService.qml b/services/LyricsService.qml index c9f782a9..213a69a9 100644 --- a/services/LyricsService.qml +++ b/services/LyricsService.qml @@ -32,6 +32,12 @@ Singleton { property var lyricsMap: ({}) + // shared headers for all NetEase requests + readonly property var _netEaseHeaders: ({ + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0", + "Referer": "https://music.163.com/" + }) + ListModel { id: lyricsModel } @@ -99,19 +105,21 @@ Singleton { } Connections { - target: Players function onActiveChanged() { root.player = Players.active; loadLyrics(); } + + target: Players } Connections { - target: root.player - ignoreUnknownSignals: true function onMetadataChanged() { loadLyrics(); } + + target: root.player + ignoreUnknownSignals: true } Process { @@ -226,12 +234,6 @@ Singleton { // NetEase - // shared headers for all NetEase requests - readonly property var _netEaseHeaders: ({ - "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0", - "Referer": "https://music.163.com/" - }) - // searches NetEase and populates the candidates model. returns the result array via the onResults callback function _searchNetEase(title, artist, reqId, onResults) { Requests.resetCookies(); diff --git a/services/Network.qml b/services/Network.qml index 7fd15dd4..b32f84a2 100644 --- a/services/Network.qml +++ b/services/Network.qml @@ -8,37 +8,21 @@ import qs.services Singleton { id: root - Component.onCompleted: { - // Trigger ethernet device detection after initialization - Qt.callLater(() => { - getEthernetDevices(); - }); - // Load saved connections on startup - Nmcli.loadSavedConnections(() => { - root.savedConnections = Nmcli.savedConnections; - root.savedConnectionSsids = Nmcli.savedConnectionSsids; - }); - // Get initial WiFi status - Nmcli.getWifiStatus(enabled => { - root.wifiEnabled = enabled; - }); - // Sync networks from Nmcli on startup - Qt.callLater(() => { - syncNetworksFromNmcli(); - }, 100); - } - readonly property list networks: [] readonly property AccessPoint active: networks.find(n => n.active) ?? null property bool wifiEnabled: true readonly property bool scanning: Nmcli.scanning - property list ethernetDevices: [] readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null property int ethernetDeviceCount: 0 property bool ethernetProcessRunning: false property var ethernetDeviceDetails: null property var wirelessDeviceDetails: null + property var pendingConnection: null + property list savedConnections: [] + property list savedConnectionSsids: [] + + signal connectionFailed(string ssid) function enableWifi(enabled: bool): void { Nmcli.enableWifi(enabled, result => { @@ -66,9 +50,6 @@ Singleton { Nmcli.rescanWifi(); } - property var pendingConnection: null - signal connectionFailed(string ssid) - function connectToNetwork(ssid: string, password: string, bssid: string, callback: var): void { // Set up pending connection tracking if callback provided if (callback) { @@ -159,20 +140,6 @@ Singleton { }); } - property list savedConnections: [] - property list savedConnectionSsids: [] - - // Sync saved connections from Nmcli when they're updated - Connections { - target: Nmcli - function onSavedConnectionsChanged() { - root.savedConnections = Nmcli.savedConnections; - } - function onSavedConnectionSsidsChanged() { - root.savedConnectionSsids = Nmcli.savedConnectionSsids; - } - } - function syncNetworksFromNmcli(): void { const rNetworks = root.networks; const nNetworks = Nmcli.networks; @@ -217,23 +184,6 @@ Singleton { } } - component AccessPoint: QtObject { - required property var lastIpcObject - readonly property string ssid: lastIpcObject.ssid - readonly property string bssid: lastIpcObject.bssid - readonly property int strength: lastIpcObject.strength - readonly property int frequency: lastIpcObject.frequency - readonly property bool active: lastIpcObject.active - readonly property string security: lastIpcObject.security - readonly property bool isSecure: security.length > 0 - } - - Component { - id: apComp - - AccessPoint {} - } - function hasSavedProfile(ssid: string): bool { // Use Nmcli's hasSavedProfile which has the same logic return Nmcli.hasSavedProfile(ssid); @@ -310,6 +260,39 @@ Singleton { return octets.join("."); } + Component.onCompleted: { + // Trigger ethernet device detection after initialization + Qt.callLater(() => { + getEthernetDevices(); + }); + // Load saved connections on startup + Nmcli.loadSavedConnections(() => { + root.savedConnections = Nmcli.savedConnections; + root.savedConnectionSsids = Nmcli.savedConnectionSsids; + }); + // Get initial WiFi status + Nmcli.getWifiStatus(enabled => { + root.wifiEnabled = enabled; + }); + // Sync networks from Nmcli on startup + Qt.callLater(() => { + syncNetworksFromNmcli(); + }, 100); + } + + // Sync saved connections from Nmcli when they're updated + Connections { + function onSavedConnectionsChanged() { + root.savedConnections = Nmcli.savedConnections; + } + + function onSavedConnectionSsidsChanged() { + root.savedConnectionSsids = Nmcli.savedConnectionSsids; + } + + target: Nmcli + } + Timer { id: monitorDebounce @@ -329,4 +312,21 @@ Singleton { onRead: monitorDebounce.start() } } + + component AccessPoint: QtObject { + required property var lastIpcObject + readonly property string ssid: lastIpcObject.ssid + readonly property string bssid: lastIpcObject.bssid + readonly property int strength: lastIpcObject.strength + readonly property int frequency: lastIpcObject.frequency + readonly property bool active: lastIpcObject.active + readonly property string security: lastIpcObject.security + readonly property bool isSecure: security.length > 0 + } + + Component { + id: apComp + + AccessPoint {} + } } diff --git a/services/Nmcli.qml b/services/Nmcli.qml index 9fa753cc..18fb02c8 100644 --- a/services/Nmcli.qml +++ b/services/Nmcli.qml @@ -24,12 +24,10 @@ Singleton { property var wifiConnectionQueue: [] property int currentSsidQueryIndex: 0 property var pendingConnection: null - signal connectionFailed(string ssid) property var wirelessDeviceDetails: null property var ethernetDeviceDetails: null property list ethernetDevices: [] readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null - property list activeProcesses: [] // Constants @@ -55,6 +53,8 @@ Singleton { readonly property string connectionParamPassword: "password" readonly property string connectionParamBssid: "802-11-wireless.bssid" + signal connectionFailed(string ssid) + function detectPasswordRequired(error: string): bool { if (!error || error.length === 0) { return false; diff --git a/services/Notifs.qml b/services/Notifs.qml index 86b906dd..2ada0f39 100644 --- a/services/Notifs.qml +++ b/services/Notifs.qml @@ -114,8 +114,6 @@ Singleton { } IpcHandler { - target: "notifs" - function clear(): void { for (const notif of root.list.slice()) notif.close(); @@ -136,6 +134,8 @@ Singleton { function disableDnd(): void { props.dnd = false; } + + target: "notifs" } component Notif: QtObject { @@ -227,8 +227,6 @@ Singleton { } readonly property Connections conn: Connections { - target: notif.notification - function onClosed(): void { notif.close(); } @@ -282,6 +280,8 @@ Singleton { function onHintsChanged(): void { notif.hints = notif.notification.hints; } + + target: notif.notification } function updateTimeStr(): void { diff --git a/services/Players.qml b/services/Players.qml index 1191696a..c55cc09a 100644 --- a/services/Players.qml +++ b/services/Players.qml @@ -21,8 +21,6 @@ Singleton { } Connections { - target: active - function onPostTrackChanged() { if (!Config.utilities.toasts.nowPlaying) { return; @@ -31,6 +29,8 @@ Singleton { Toaster.toast(qsTr("Now Playing"), qsTr("%1 - %2").arg(active.trackArtist).arg(active.trackTitle), "music_note"); } } + + target: active } PersistentProperties { @@ -78,8 +78,6 @@ Singleton { } IpcHandler { - target: "mpris" - function getActive(prop: string): string { const active = root.active; return active ? active[prop] ?? "Invalid property" : "No active player"; @@ -122,5 +120,7 @@ Singleton { function stop(): void { root.active?.stop(); } + + target: "mpris" } } diff --git a/services/Recorder.qml b/services/Recorder.qml index 6eddce94..4c9f9fd5 100644 --- a/services/Recorder.qml +++ b/services/Recorder.qml @@ -72,11 +72,11 @@ Singleton { } Connections { - target: Time // enabled: props.running && !props.paused - function onSecondsChanged(): void { props.elapsed++; } + + target: Time } } diff --git a/services/Wallpapers.qml b/services/Wallpapers.qml index cb96bc56..c1f3c184 100644 --- a/services/Wallpapers.qml +++ b/services/Wallpapers.qml @@ -46,8 +46,6 @@ Searcher { }) IpcHandler { - target: "wallpaper" - function get(): string { return root.actualCurrent; } @@ -59,6 +57,8 @@ Searcher { function list(): string { return root.list.map(w => w.path).join("\n"); } + + target: "wallpaper" } FileView { diff --git a/services/Weather.qml b/services/Weather.qml index 98e29bbb..36e69265 100644 --- a/services/Weather.qml +++ b/services/Weather.qml @@ -210,10 +210,11 @@ Singleton { onLocChanged: fetchWeatherData() Connections { - target: Config.services function onWeatherLocationChanged(): void { root.reload(); } + + target: Config.services } // Refresh current location hourly diff --git a/utils/SysInfo.qml b/utils/SysInfo.qml index 19aa4a7a..aaa1ad31 100644 --- a/utils/SysInfo.qml +++ b/utils/SysInfo.qml @@ -50,11 +50,11 @@ Singleton { } Connections { - target: Config.general - function onLogoChanged(): void { osRelease.reload(); } + + target: Config.general } Timer {