diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 420b67e..22d41fd 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -19,6 +19,7 @@ Variants { implicitHeight: Style.barHeight * scaling color: "transparent" + // If no bar display activated in settings, then show them all visible: modelData ? (Settings.data.bar.monitors.includes(modelData.name) || (Settings.data.bar.monitors.length === 0)) : false diff --git a/Modules/Dock/Dock.qml b/Modules/Dock/Dock.qml index bb0f9c8..701ac7d 100644 --- a/Modules/Dock/Dock.qml +++ b/Modules/Dock/Dock.qml @@ -40,7 +40,7 @@ NLoader { PanelWindow { id: dockWindow - // Dock works differently from bar, it is show only if toggled in Settings/Display + // Dock is only shown if explicitely toggled visible: modelData ? Settings.data.dock.monitors.includes(modelData.name) : false screen: modelData diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml index 99cc20e..5858e4e 100644 --- a/Modules/Notification/Notification.qml +++ b/Modules/Notification/Notification.qml @@ -8,182 +8,190 @@ import qs.Services import qs.Widgets // Simple notification popup - displays multiple notifications -PanelWindow { - id: root +Variants { + model: Quickshell.screens - readonly property real scaling: Scaling.scale(screen) + PanelWindow { + id: root - color: "transparent" - visible: notificationService.notificationModel.count > 0 - anchors.top: true - anchors.right: true - margins.top: (Style.barHeight + Style.marginMedium) * scaling - margins.right: Style.marginMedium * scaling - implicitWidth: 360 * scaling - implicitHeight: Math.min(notificationStack.implicitHeight, (notificationService.maxVisible * 120) * scaling) - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.exclusionMode: ExclusionMode.Ignore + required property ShellScreen modelData + readonly property real scaling: Scaling.scale(screen) - // Use the notification service singleton - property var notificationService: NotificationService + // Access the notification model from the service + property ListModel notificationModel: NotificationService.notificationModel - // Access the notification model from the service - property ListModel notificationModel: notificationService.notificationModel + // Track notifications being removed for animation + property var removingNotifications: ({}) - // Track notifications being removed for animation - property var removingNotifications: ({}) + screen: modelData + color: "transparent" - // Connect to animation signal from service - Component.onCompleted: { - notificationService.animateAndRemove.connect(function (notification, index) { - // Find the delegate and trigger its animation - if (notificationStack.children && notificationStack.children[index]) { - let delegate = notificationStack.children[index] - if (delegate && delegate.animateOut) { - delegate.animateOut() - } - } - }) - } + // If no notification display activated in settings, then show them all + visible: modelData ? (Settings.data.notifications.monitors.includes(modelData.name) + || (Settings.data.notifications.monitors.length === 0)) + && (NotificationService.notificationModel.count > 0) : false - // Main notification container - Column { - id: notificationStack - anchors.top: parent.top - anchors.right: parent.right - spacing: 8 * scaling - width: 360 * scaling - visible: true + anchors.top: true + anchors.right: true + margins.top: (Style.barHeight + Style.marginMedium) * scaling + margins.right: Style.marginMedium * scaling + implicitWidth: 360 * scaling + implicitHeight: Math.min(notificationStack.implicitHeight, (NotificationService.maxVisible * 120) * scaling) + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.exclusionMode: ExclusionMode.Ignore - // Multiple notifications display - Repeater { - model: notificationModel - delegate: Rectangle { - width: 360 * scaling - height: Math.max(80 * scaling, contentColumn.implicitHeight + (Style.marginMedium * 2 * scaling)) - clip: true - radius: Style.radiusMedium * scaling - border.color: Colors.mPrimary - border.width: Math.max(1, Style.borderThin * scaling) - color: Colors.mSurface - - // Animation properties - property real scaleValue: 0.8 - property real opacityValue: 0.0 - property bool isRemoving: false - - // Scale and fade-in animation - scale: scaleValue - opacity: opacityValue - - // Animate in when the item is created - Component.onCompleted: { - scaleValue = 1.0 - opacityValue = 1.0 - } - - // Animate out when being removed - function animateOut() { - isRemoving = true - scaleValue = 0.8 - opacityValue = 0.0 - } - - // Timer for delayed removal after animation - Timer { - id: removalTimer - interval: Style.animationSlow - repeat: false - onTriggered: { - notificationService.forceRemoveNotification(model.rawNotification) + // Connect to animation signal from service + Component.onCompleted: { + NotificationService.animateAndRemove.connect(function (notification, index) { + // Find the delegate and trigger its animation + if (notificationStack.children && notificationStack.children[index]) { + let delegate = notificationStack.children[index] + if (delegate && delegate.animateOut) { + delegate.animateOut() } } + }) + } - // Check if this notification is being removed - onIsRemovingChanged: { - if (isRemoving) { - // Remove from model after animation completes - removalTimer.start() + // Main notification container + Column { + id: notificationStack + anchors.top: parent.top + anchors.right: parent.right + spacing: 8 * scaling + width: 360 * scaling + visible: true + + // Multiple notifications display + Repeater { + model: notificationModel + delegate: Rectangle { + width: 360 * scaling + height: Math.max(80 * scaling, contentColumn.implicitHeight + (Style.marginMedium * 2 * scaling)) + clip: true + radius: Style.radiusMedium * scaling + border.color: Colors.mPrimary + border.width: Math.max(1, Style.borderThin * scaling) + color: Colors.mSurface + + // Animation properties + property real scaleValue: 0.8 + property real opacityValue: 0.0 + property bool isRemoving: false + + // Scale and fade-in animation + scale: scaleValue + opacity: opacityValue + + // Animate in when the item is created + Component.onCompleted: { + scaleValue = 1.0 + opacityValue = 1.0 } - } - // Animation behaviors - Behavior on scale { - NumberAnimation { - duration: Style.animationSlow - easing.type: Easing.OutExpo - //easing.type: Easing.OutBack looks better but notification get clipped on all sides + // Animate out when being removed + function animateOut() { + isRemoving = true + scaleValue = 0.8 + opacityValue = 0.0 } - } - Behavior on opacity { - NumberAnimation { - duration: Style.animationNormal - easing.type: Easing.OutQuad + // Timer for delayed removal after animation + Timer { + id: removalTimer + interval: Style.animationSlow + repeat: false + onTriggered: { + NotificationService.forceRemoveNotification(model.rawNotification) + } } - } - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Style.marginMedium * scaling - spacing: Style.marginSmall * scaling + // Check if this notification is being removed + onIsRemovingChanged: { + if (isRemoving) { + // Remove from model after animation completes + removalTimer.start() + } + } - RowLayout { + // Animation behaviors + Behavior on scale { + NumberAnimation { + duration: Style.animationSlow + easing.type: Easing.OutExpo + //easing.type: Easing.OutBack looks better but notification get clipped on all sides + } + } + + Behavior on opacity { + NumberAnimation { + duration: Style.animationNormal + easing.type: Easing.OutQuad + } + } + + Column { + id: contentColumn + anchors.fill: parent + anchors.margins: Style.marginMedium * scaling spacing: Style.marginSmall * scaling + + RowLayout { + spacing: Style.marginSmall * scaling + NText { + text: (model.appName || model.desktopEntry) || "Unknown App" + color: Colors.mSecondary + font.pointSize: Style.fontSizeSmall * scaling + } + Rectangle { + width: 6 * scaling + height: 6 * scaling + radius: 3 * scaling + color: (model.urgency === NotificationUrgency.Critical) ? Colors.mError : (model.urgency === NotificationUrgency.Low) ? Colors.mOnSurface : Colors.mPrimary + Layout.alignment: Qt.AlignVCenter + } + Item { + Layout.fillWidth: true + } + NText { + text: NotificationService.formatTimestamp(model.timestamp) + color: Colors.mOnSurface + font.pointSize: Style.fontSizeSmall * scaling + } + } + NText { - text: (model.appName || model.desktopEntry) || "Unknown App" - color: Colors.mSecondary - font.pointSize: Style.fontSizeSmall * scaling - } - Rectangle { - width: 6 * scaling - height: 6 * scaling - radius: 3 * scaling - color: (model.urgency === NotificationUrgency.Critical) ? Colors.mError : (model.urgency === NotificationUrgency.Low) ? Colors.mOnSurface : Colors.mPrimary - Layout.alignment: Qt.AlignVCenter - } - Item { - Layout.fillWidth: true - } - NText { - text: notificationService.formatTimestamp(model.timestamp) + text: model.summary || "No summary" + font.pointSize: Style.fontSizeLarge * scaling + font.weight: Style.fontWeightBold color: Colors.mOnSurface + wrapMode: Text.Wrap + width: 300 * scaling + maximumLineCount: 3 + elide: Text.ElideRight + } + + NText { + text: model.body || "" font.pointSize: Style.fontSizeSmall * scaling + color: Colors.mOnSurface + wrapMode: Text.Wrap + width: 300 * scaling + maximumLineCount: 5 + elide: Text.ElideRight } } - NText { - text: model.summary || "No summary" - font.pointSize: Style.fontSizeLarge * scaling - font.weight: Style.fontWeightBold - color: Colors.mOnSurface - wrapMode: Text.Wrap - width: 300 * scaling - maximumLineCount: 3 - elide: Text.ElideRight - } - - NText { - text: model.body || "" - font.pointSize: Style.fontSizeSmall * scaling - color: Colors.mOnSurface - wrapMode: Text.Wrap - width: 300 * scaling - maximumLineCount: 5 - elide: Text.ElideRight - } - } - - NIconButton { - sizeMultiplier: 0.8 - showBorder: false - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Style.marginSmall * scaling - icon: "close" - onClicked: { - animateOut() + NIconButton { + sizeMultiplier: 0.8 + showBorder: false + anchors.top: parent.top + anchors.right: parent.right + anchors.margins: Style.marginSmall * scaling + icon: "close" + onClicked: { + animateOut() + } } } } diff --git a/Modules/Settings/Tabs/DisplayTab.qml b/Modules/Settings/Tabs/DisplayTab.qml index 3d1211a..3282813 100644 --- a/Modules/Settings/Tabs/DisplayTab.qml +++ b/Modules/Settings/Tabs/DisplayTab.qml @@ -47,6 +47,95 @@ Item { color: Colors.mOnSurface } + NText { + text: "By default, all bars are displayed. Select one or more below to narrow your view." + font.pointSize: Style.fontSize * scaling + color: Colors.mOnSurfaceVariant + } + + Repeater { + model: Quickshell.screens || [] + delegate: Rectangle { + Layout.fillWidth: true + radius: Style.radiusMedium * scaling + color: Colors.mSurface + border.color: Colors.mOutline + border.width: Math.max(1, Style.borderThin * scaling) + implicitHeight: contentCol.implicitHeight + Style.marginXL * 2 * scaling + + ColumnLayout { + id: contentCol + anchors.fill: parent + anchors.margins: Style.marginLarge * scaling + spacing: Style.marginTiniest * scaling + + NText { + text: (modelData.name || "Unknown") + font.pointSize: Style.fontSizeLarge * scaling + font.weight: Style.fontWeightBold + color: Colors.mSecondary + } + + NText { + text: `Resolution: ${modelData.width}x${modelData.height} - Position: (${modelData.x}, ${modelData.y})` + font.pointSize: Style.fontSizeSmall * scaling + color: Colors.mOnSurface + } + + ColumnLayout { + spacing: Style.marginLarge * scaling + + NToggle { + label: "Bar" + description: "Enable the top bar on this monitor" + value: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1 + onToggled: function (newValue) { + if (newValue) { + Settings.data.bar.monitors = addMonitor(Settings.data.bar.monitors, modelData.name) + } else { + Settings.data.bar.monitors = removeMonitor(Settings.data.bar.monitors, modelData.name) + } + } + } + + NToggle { + label: "Dock" + description: "Enable the dock on this monitor" + value: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1 + onToggled: function (newValue) { + if (newValue) { + Settings.data.dock.monitors = addMonitor(Settings.data.dock.monitors, modelData.name) + } else { + Settings.data.dock.monitors = removeMonitor(Settings.data.dock.monitors, modelData.name) + } + } + } + + NToggle { + label: "Notifications" + description: "Enable notifications on this monitor" + value: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 + onToggled: function (newValue) { + if (newValue) { + Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors, + modelData.name) + } else { + Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors, + modelData.name) + } + } + } + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginLarge * 2 * scaling + Layout.bottomMargin: Style.marginLarge * scaling + } + // Brightness Section ColumnLayout { spacing: Style.marginSmall * scaling @@ -92,89 +181,6 @@ Item { } } - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginLarge * 2 * scaling - Layout.bottomMargin: Style.marginLarge * scaling - } - - Repeater { - model: Quickshell.screens || [] - delegate: Rectangle { - Layout.fillWidth: true - radius: Style.radiusMedium * scaling - color: Colors.mSurface - border.color: Colors.mOutline - border.width: Math.max(1, Style.borderThin * scaling) - implicitHeight: contentCol.implicitHeight + Style.marginXL * 2 * scaling - - ColumnLayout { - id: contentCol - anchors.fill: parent - anchors.margins: Style.marginLarge * scaling - spacing: Style.marginTiniest * scaling - - NText { - text: (modelData.name || "Unknown") - font.pointSize: Style.fontSizeLarge * scaling - font.weight: Style.fontWeightBold - color: Colors.mSecondary - } - - NText { - text: `Resolution: ${modelData.width}x${modelData.height} - Position: (${modelData.x}, ${modelData.y})` - font.pointSize: Style.fontSizeSmall * scaling - color: Colors.mOnSurface - } - - ColumnLayout { - spacing: Style.marginLarge * scaling - - NToggle { - label: "Bar" - description: "Display the top bar on this monitor" - value: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1 - onToggled: function (newValue) { - if (newValue) { - Settings.data.bar.monitors = addMonitor(Settings.data.bar.monitors, modelData.name) - } else { - Settings.data.bar.monitors = removeMonitor(Settings.data.bar.monitors, modelData.name) - } - } - } - - NToggle { - label: "Dock" - description: "Display the dock on this monitor" - value: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1 - onToggled: function (newValue) { - if (newValue) { - Settings.data.dock.monitors = addMonitor(Settings.data.dock.monitors, modelData.name) - } else { - Settings.data.dock.monitors = removeMonitor(Settings.data.dock.monitors, modelData.name) - } - } - } - - NToggle { - label: "Notifications" - description: "Display notifications on this monitor" - value: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 - onToggled: function (newValue) { - if (newValue) { - Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors, - modelData.name) - } else { - Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors, - modelData.name) - } - } - } - } - } - } - } - Item { Layout.fillHeight: true } diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml index c0eb9fc..9437c62 100644 --- a/Modules/SidePanel/Cards/MediaCard.qml +++ b/Modules/SidePanel/Cards/MediaCard.qml @@ -339,15 +339,5 @@ NBox { Layout.alignment: Qt.AlignHCenter } } - - // CircularSpectrum { - // visible: Settings.data.audio.visualizerType == "radial" - // values: Cava.values - // innerRadius: 30 * scaling // Position just outside 60x60 album art - // outerRadius: 48 * scaling // Extend bars outward from album art - // fillColor: Colors.mPrimary - // strokeColor: Colors.mPrimary - // strokeWidth: 0 * scaling - // } } } diff --git a/Services/BrightnessService.qml b/Services/BrightnessService.qml index cd6cabd..9dd9e15 100644 --- a/Services/BrightnessService.qml +++ b/Services/BrightnessService.qml @@ -209,11 +209,11 @@ Singleton { function getStoredBrightness(): real { // Try to get stored brightness for this specific monitor var stored = Settings.data.brightness.monitorBrightness.find(m => { - if (m !== null) { - return m.name === modelData.name - } - return false - }) + if (m !== null) { + return m.name === modelData.name + } + return false + }) if (stored) { return stored.brightness / 100 } @@ -230,11 +230,11 @@ Singleton { // Update monitor-specific brightness var monitorIndex = Settings.data.brightness.monitorBrightness.findIndex(m => { - if (m !== null) { - return m.name === modelData.name - } - return -1 - }) + if (m !== null) { + return m.name === modelData.name + } + return -1 + }) var monitorData = { "name": modelData.name, "brightness": brightnessPercent,