From 744fa54ae06ff4571fa59d2e9c539b9dabc461c3 Mon Sep 17 00:00:00 2001 From: bbedward Date: Sun, 23 Aug 2026 14:34:19 -0400 Subject: [PATCH] island: resize to notifications based on title size --- .../DankIsland/Activities/HomeCompact.qml | 208 ++++++++---------- .../Activities/NotificationCompact.qml | 35 ++- .../Modules/DankIsland/DankIslandSurface.qml | 1 + .../Modules/DankIsland/IslandController.qml | 12 +- 4 files changed, 134 insertions(+), 122 deletions(-) diff --git a/quickshell/Modules/DankIsland/Activities/HomeCompact.qml b/quickshell/Modules/DankIsland/Activities/HomeCompact.qml index 98d4f6c84..9a7829dbd 100644 --- a/quickshell/Modules/DankIsland/Activities/HomeCompact.qml +++ b/quickshell/Modules/DankIsland/Activities/HomeCompact.qml @@ -20,27 +20,17 @@ Item { readonly property real itemSpacing: root.tight ? Theme.spacingXS : Theme.spacingS readonly property real dotSize: root.tight ? 3 : 4 readonly property bool weatherSlotEnabled: root.controller.homeWeatherSlot !== "hidden" - readonly property bool batteryStatus: BatteryService.batteryAvailable - readonly property var leftSlotIds: root.slotsForSide("left") - readonly property var rightSlotIds: root.slotsForSide("right") - readonly property var clusterIds: root.clusterItemsForSide("left").concat(["clock"]).concat(root.clusterItemsForSide("right")) + readonly property var clusterIds: root.itemsForSide("left").concat(["clock"]).concat(root.itemsForSide("right")) property bool weatherRefHeld: false - function slotsForSide(side) { + function itemsForSide(side) { const ids = []; if (root.controller.homeMediaSlot === side) ids.push("media"); - if (root.controller.homeStatusSlot === side && !root.batteryStatus) - ids.push("status"); - return ids; - } - - function clusterItemsForSide(side) { - const ids = []; if (root.controller.homeWeatherSlot === side) ids.push("weather"); - if (root.controller.homeStatusSlot === side && root.batteryStatus) - ids.push("battery"); + if (root.controller.homeStatusSlot === side) + ids.push("status"); return ids; } @@ -76,66 +66,6 @@ Item { precision: SettingsData.showSeconds ? SystemClock.Seconds : SystemClock.Minutes } - component HomeActionSlot: Item { - id: slot - - required property string actionId - - readonly property bool isMedia: slot.actionId === "media" - - width: root.slotSize - height: root.slotSize - - Rectangle { - anchors.fill: parent - radius: height / 2 - color: slotArea.containsMouse ? Theme.surfaceTextHover : "transparent" - } - - AudioVisualization { - anchors.centerIn: parent - width: root.tight ? 16 : 20 - height: width - maxBarHeight: Math.max(3, height - 2) - idleIconName: "graphic_eq" - visible: slot.isMedia && root.controller.mediaAvailable - } - - DankIcon { - anchors.centerIn: parent - visible: slot.isMedia && !root.controller.mediaAvailable - name: "search" - size: root.iconSize - color: Theme.surfaceTextMedium - } - - DankIcon { - anchors.centerIn: parent - visible: !slot.isMedia - name: "tune" - size: root.iconSize - color: Theme.surfaceText - } - - IslandSlotHoverArea { - id: slotArea - - anchors.fill: parent - controller: root.controller - onClicked: { - if (!slot.isMedia) { - root.controller.requestControlCenter("", false); - return; - } - if (root.controller.mediaAvailable) { - root.controller.requestActivity("media", false, false); - return; - } - root.controller.requestLauncher("", "", false); - } - } - } - component ClusterDot: Rectangle { property bool unread: false @@ -146,6 +76,16 @@ Item { color: unread ? Theme.secondary : Theme.primary } + component HoverBackdrop: Rectangle { + property bool hovered: false + + anchors.centerIn: parent + width: parent.width + Theme.spacingS + height: root.slotSize + radius: height / 2 + color: hovered ? Theme.surfaceTextHover : "transparent" + } + component ClusterItem: Row { id: item @@ -153,8 +93,10 @@ Item { property int itemIndex: 0 readonly property bool isClock: item.itemId === "clock" + readonly property bool isMedia: item.itemId === "media" readonly property bool isWeather: item.itemId === "weather" - readonly property bool isBattery: item.itemId === "battery" + readonly property bool isStatus: item.itemId === "status" + readonly property bool usesBattery: item.isStatus && BatteryService.batteryAvailable spacing: root.itemSpacing @@ -177,7 +119,7 @@ Item { anchors.verticalCenter: parent.verticalCenter text: root.timeText color: Theme.surfaceText - font.pixelSize: root.tight ? Theme.fontSizeSmall : Theme.fontSizeMedium + font.pixelSize: Theme.fontSizeSmall font.weight: Font.DemiBold } @@ -189,7 +131,7 @@ Item { IslandSlotHoverArea { anchors.centerIn: parent width: parent.width + Theme.spacingS - height: parent.height + Theme.spacingS + height: root.slotSize enabled: unreadDot.unread controller: root.controller onClicked: root.controller.requestNotificationCenter(false) @@ -206,17 +148,56 @@ Item { } } + Item { + width: root.iconSize + Theme.spacingXS + height: root.slotSize + visible: item.isMedia + + HoverBackdrop { + hovered: mediaArea.containsMouse + } + + AudioVisualization { + anchors.centerIn: parent + width: root.iconSize + Theme.spacingXS + height: width + maxBarHeight: Math.max(3, height - 2) + idleIconName: "graphic_eq" + visible: root.controller.mediaAvailable + } + + DankIcon { + anchors.centerIn: parent + visible: !root.controller.mediaAvailable + name: "search" + size: root.iconSize + color: Theme.surfaceTextMedium + } + + IslandSlotHoverArea { + id: mediaArea + + anchors.centerIn: parent + width: parent.width + Theme.spacingS + height: root.slotSize + controller: root.controller + onClicked: { + if (root.controller.mediaAvailable) { + root.controller.requestActivity("media", false, false); + return; + } + root.controller.requestLauncher("", "", false); + } + } + } + Item { width: weatherRow.implicitWidth height: root.slotSize visible: item.isWeather - Rectangle { - anchors.centerIn: parent - width: parent.width + Theme.spacingS - height: parent.height - radius: height / 2 - color: weatherArea.containsMouse ? Theme.surfaceTextHover : "transparent" + HoverBackdrop { + hovered: weatherArea.containsMouse } Row { @@ -246,32 +227,45 @@ Item { anchors.centerIn: parent width: parent.width + Theme.spacingS - height: parent.height + height: root.slotSize controller: root.controller onClicked: root.controller.requestWeather(false) } } Item { - width: batteryMeter.width + width: item.usesBattery ? batteryMeter.width : root.iconSize height: root.slotSize - visible: item.isBattery + visible: item.isStatus + + HoverBackdrop { + hovered: statusArea.containsMouse && !item.usesBattery + } BatteryMeter { id: batteryMeter anchors.centerIn: parent + visible: item.usesBattery thickness: root.tight ? 12 : 14 - hovered: batteryArea.containsMouse + hovered: statusArea.containsMouse outlined: SettingsData.dankIslandBatteryStyle === "outline" } + DankIcon { + anchors.centerIn: parent + visible: !item.usesBattery + name: "tune" + size: root.iconSize + color: Theme.surfaceText + } + IslandSlotHoverArea { - id: batteryArea + id: statusArea anchors.centerIn: parent width: parent.width + Theme.spacingS - height: parent.height + height: root.slotSize controller: root.controller onClicked: root.controller.requestControlCenter("", false) } @@ -282,39 +276,17 @@ Item { id: compactRow anchors.centerIn: parent - spacing: root.controller.homeClusterGap + height: root.slotSize + spacing: root.itemSpacing Repeater { - model: root.leftSlotIds + model: root.clusterIds - HomeActionSlot { + ClusterItem { required property var modelData - actionId: String(modelData) - } - } - - Row { - height: root.slotSize - spacing: root.itemSpacing - - Repeater { - model: root.clusterIds - - ClusterItem { - required property var modelData - required property int index - itemId: String(modelData) - itemIndex: index - } - } - } - - Repeater { - model: root.rightSlotIds - - HomeActionSlot { - required property var modelData - actionId: String(modelData) + required property int index + itemId: String(modelData) + itemIndex: index } } } diff --git a/quickshell/Modules/DankIsland/Activities/NotificationCompact.qml b/quickshell/Modules/DankIsland/Activities/NotificationCompact.qml index f4c792301..27980c05f 100644 --- a/quickshell/Modules/DankIsland/Activities/NotificationCompact.qml +++ b/quickshell/Modules/DankIsland/Activities/NotificationCompact.qml @@ -8,9 +8,38 @@ Item { id: root required property var notificationModel + required property var controller property bool dense: false property real iconSize: 36 + readonly property string headerText: root.notificationModel.appName + (root.notificationModel.timeText ? " · " + root.notificationModel.timeText : "") + readonly property string summaryText: root.dense && root.notificationModel.appName ? root.notificationModel.appName + " · " + root.notificationModel.summary : root.notificationModel.summary + readonly property real criticalWidth: root.notificationModel.critical ? 3 + Theme.spacingS : 0 + readonly property real measuredWidth: Theme.spacingS * 3 + root.criticalWidth + root.iconSize + Math.max(root.dense ? 0 : headerMetrics.width, summaryMetrics.width) + + function pushMeasuredWidth() { + root.controller.setNotificationContentWidth(root.measuredWidth); + } + + onMeasuredWidthChanged: root.pushMeasuredWidth() + Component.onCompleted: root.pushMeasuredWidth() + + StyledTextMetrics { + id: headerMetrics + + font.pixelSize: Theme.fontSizeSmall + font.weight: Font.Medium + text: root.headerText + } + + StyledTextMetrics { + id: summaryMetrics + + font.pixelSize: root.dense ? Theme.fontSizeSmall : Theme.fontSizeMedium + font.weight: Font.DemiBold + text: root.summaryText + } + Row { anchors { fill: parent @@ -40,13 +69,13 @@ Item { Column { anchors.verticalCenter: parent.verticalCenter - width: parent.width - root.iconSize - parent.spacing - (root.notificationModel.critical ? 3 + parent.spacing : 0) + width: parent.width - root.iconSize - parent.spacing - root.criticalWidth spacing: 1 StyledText { width: parent.width visible: !root.dense - text: root.notificationModel.appName + (root.notificationModel.timeText ? " · " + root.notificationModel.timeText : "") + text: root.headerText color: Theme.surfaceTextSecondary font.pixelSize: Theme.fontSizeSmall font.weight: Font.Medium @@ -55,7 +84,7 @@ Item { StyledText { width: parent.width - text: root.dense && root.notificationModel.appName ? root.notificationModel.appName + " · " + root.notificationModel.summary : root.notificationModel.summary + text: root.summaryText color: Theme.surfaceText font.pixelSize: root.dense ? Theme.fontSizeSmall : Theme.fontSizeMedium font.weight: Font.DemiBold diff --git a/quickshell/Modules/DankIsland/DankIslandSurface.qml b/quickshell/Modules/DankIsland/DankIslandSurface.qml index 1e2ab7561..fe10ec264 100644 --- a/quickshell/Modules/DankIsland/DankIslandSurface.qml +++ b/quickshell/Modules/DankIsland/DankIslandSurface.qml @@ -464,6 +464,7 @@ Item { NotificationCompact { notificationModel: root.notificationModel + controller: root.controller dense: root.controller.compactDense iconSize: root.controller.compactIconSize } diff --git a/quickshell/Modules/DankIsland/IslandController.qml b/quickshell/Modules/DankIsland/IslandController.qml index aa0659b13..b52df6ea4 100644 --- a/quickshell/Modules/DankIsland/IslandController.qml +++ b/quickshell/Modules/DankIsland/IslandController.qml @@ -66,6 +66,9 @@ QtObject { property real homeContentWidth: 200 property real mediaContentWidth: 360 readonly property real mediaCompactMaxWidth: 360 + property real notificationContentWidth: 0 + readonly property real notificationCompactMinWidth: compactDense ? 200 : 240 + readonly property real notificationCompactMaxWidth: compactDense ? 320 : 360 signal sessionStarted(string activityId) @@ -76,6 +79,13 @@ QtObject { homeContentWidth = next; } + function setNotificationContentWidth(width) { + const next = Math.ceil(width); + if (!isFinite(next) || next <= 0 || Math.abs(next - notificationContentWidth) < 2) + return; + notificationContentWidth = next; + } + function setMediaContentWidth(width) { const next = Math.ceil(Math.min(root.mediaCompactMaxWidth, width)); if (!isFinite(next) || next <= 0 || Math.abs(next - mediaContentWidth) < 2) @@ -306,7 +316,7 @@ QtObject { readonly property var weatherExpandedTarget: sheetTarget(SettingsData.showWeekNumber ? 736 : 700, 452) readonly property var systemCompactTarget: pillTarget(SettingsData.osdAlwaysShowValue ? 330 : 282, compactFaceHeight) readonly property var systemExpandedTarget: sheetTarget(460, 176) - readonly property var notificationCompactTarget: pillTarget(compactDense ? 320 : 360, compactFaceHeight) + readonly property var notificationCompactTarget: pillTarget(Math.ceil(Math.max(notificationCompactMinWidth, Math.min(notificationCompactMaxWidth, notificationContentWidth))), compactFaceHeight) readonly property var notificationExpandedTarget: sheetTarget(520, 220) readonly property var notificationCenterExpandedTarget: sheetTarget(480, notificationCenterHeight)