diff --git a/dank-qml-common b/dank-qml-common index ff99ec8a9..a90d34465 160000 --- a/dank-qml-common +++ b/dank-qml-common @@ -1 +1 @@ -Subproject commit ff99ec8a93c4a52d792e7020575540582f249ea9 +Subproject commit a90d3446572b924454f60f34dec2871d26e31af5 diff --git a/flake.lock b/flake.lock index 22f5e1882..389ac0a53 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "dank-qml-common": { "flake": false, "locked": { - "lastModified": 1789755182, - "narHash": "sha256-47BBqvpzKSKo65gRnGirwulJ/c6N3Dg+vEfErwXTu58=", + "lastModified": 1789762202, + "narHash": "sha256-p2t+1y5OIRz0w1+06W/hBxKtTGSAP4XzHfzP3RZpCkA=", "owner": "AvengeMedia", "repo": "dank-qml-common", - "rev": "ff99ec8a93c4a52d792e7020575540582f249ea9", + "rev": "a90d3446572b924454f60f34dec2871d26e31af5", "type": "github" }, "original": { diff --git a/quickshell/Modules/ControlCenter/Components/CcDetailPage.qml b/quickshell/Modules/ControlCenter/Components/CcDetailPage.qml index 324deb9e2..3a7d77d52 100644 --- a/quickshell/Modules/ControlCenter/Components/CcDetailPage.qml +++ b/quickshell/Modules/ControlCenter/Components/CcDetailPage.qml @@ -35,7 +35,7 @@ Item { } readonly property real offscreenX: I18n.isRtl ? -width : width - visible: shownSection !== "" || panel.x !== offscreenX + visible: shownSection !== "" function dismissTransient() { const item = pageItem; diff --git a/quickshell/Modules/DankDash/DashMetrics.qml b/quickshell/Modules/DankDash/DashMetrics.qml index d202844a5..5892cfc78 100644 --- a/quickshell/Modules/DankDash/DashMetrics.qml +++ b/quickshell/Modules/DankDash/DashMetrics.qml @@ -195,6 +195,8 @@ Singleton { readonly property real lyricsNearOpacity: 0.55 readonly property real lyricsFarOpacity: 0.3 readonly property real lyricsLineHeight: 1.25 + readonly property real lyricsLeadHeightDivisor: 12 + readonly property real lyricsLeadWidthDivisor: 11 readonly property int wheelNotch: 120 readonly property int dailyVisibleCount: 7 diff --git a/quickshell/Modules/DankDash/Media/LyricsOverlay.qml b/quickshell/Modules/DankDash/Media/LyricsOverlay.qml index b119303b1..d25aedaad 100644 --- a/quickshell/Modules/DankDash/Media/LyricsOverlay.qml +++ b/quickshell/Modules/DankDash/Media/LyricsOverlay.qml @@ -31,6 +31,7 @@ FocusScope { readonly property real currentLineY: transcript.currentItem?.y ?? 0 readonly property real shapeInset: Math.ceil(Math.min(radius, width / 2, height / 2) * (1 - Math.SQRT1_2)) readonly property bool compact: content.height < Theme.listItemTwoLineHeight * 2 + readonly property real leadFontSize: Math.round(Math.max(Theme.fontSizeXLarge, Math.min(Theme.fontSizeDisplay, transcript.height / DashMetrics.lyricsLeadHeightDivisor, transcript.width / DashMetrics.lyricsLeadWidthDivisor))) readonly property string message: { switch (controller.state) { case "loading": @@ -303,6 +304,7 @@ FocusScope { accent: modelData.chorus ? MediaAccentService.lyricsGroupAccent : MediaAccentService.lyricsAccents[(modelData.voiceIndex ?? 0) % MediaAccentService.lyricsAccents.length] synced: root.controller.synced following: root.following + leadFontSize: root.leadFontSize distance: lyric ? Math.abs(lyric.index - root.activeIndex) : 0 animationsEnabled: root.animationsEnabled inViewport: { diff --git a/quickshell/Modules/DankDash/Media/LyricsVocal.qml b/quickshell/Modules/DankDash/Media/LyricsVocal.qml index 34fd5312b..6587ba7cb 100644 --- a/quickshell/Modules/DankDash/Media/LyricsVocal.qml +++ b/quickshell/Modules/DankDash/Media/LyricsVocal.qml @@ -20,6 +20,7 @@ Item { property int distance: 0 property bool animationsEnabled: true property bool inViewport: false + property real leadFontSize: Theme.fontSizeXLarge readonly property bool current: synced && controller.sampleTime >= part.t && controller.sampleTime < part.e readonly property bool highlighted: synced && controller.sampleTime >= part.t && (current || distance === 0) @@ -102,7 +103,7 @@ Item { easing.bezierCurve: Theme.expressiveCurves.expressiveEffects } } - font.pixelSize: root.part.background || !root.emphasize ? Theme.fontSizeLarge : Theme.fontSizeXLarge + font.pixelSize: root.part.background || !root.emphasize ? Math.round(root.leadFontSize * Theme.fontSizeLarge / Theme.fontSizeXLarge) : root.leadFontSize font.weight: root.synced && !root.part.background ? Theme.fontWeightBold : Theme.fontWeightMedium scale: root.textScale Behavior on scale { diff --git a/quickshell/Modules/DankDash/Overview/ClockCard.qml b/quickshell/Modules/DankDash/Overview/ClockCard.qml index f461116e9..4ec1cc0dc 100644 --- a/quickshell/Modules/DankDash/Overview/ClockCard.qml +++ b/quickshell/Modules/DankDash/Overview/ClockCard.qml @@ -21,6 +21,9 @@ Card { } readonly property string minuteText: String(systemClock.date.getMinutes()).padStart(2, "0") readonly property string secondText: String(systemClock.date.getSeconds()).padStart(2, "0") + readonly property string dateText: showDate ? systemClock.date.toLocaleDateString(I18n.locale(), SettingsData.getEffectiveDateFormat("ddd, MMM d")) : "" + readonly property color supportingColor: tinted ? contentColor : mutedColor + readonly property real supportLine: Theme.fontSizeMedium * 1.5 entryId: "clock" tone: options.tone ?? "" @@ -38,28 +41,75 @@ Card { hours: root.hourText minutes: root.minuteText seconds: root.showSeconds ? root.secondText : "" - dateText: root.showDate ? systemClock.date.toLocaleDateString(I18n.locale(), "MMMM d") : "" - dayText: root.showDate ? systemClock.date.toLocaleDateString(I18n.locale(), "dddd") : "" + dateText: root.dateText color: root.accentColor - supportingColor: root.tinted ? root.contentColor : root.mutedColor + supportingColor: root.supportingColor } } Component { id: analogFace - DankAnalogClock { - hours: systemClock.date.getHours() - minutes: systemClock.date.getMinutes() - seconds: systemClock.date.getSeconds() - showSeconds: root.showSeconds - showNumbers: root.options.numbers === true - numbersOutside: root.tinted - dateText: root.showDate ? systemClock.date.toLocaleDateString(I18n.locale(), "MMM d") : "" - color: root.tinted ? root.onAccentColor : root.accentColor - numberColor: root.accentColor - backgroundColor: root.tinted ? root.accentColor : root.chipColor - facePadding: 0 + Item { + id: face + + readonly property real span: Math.min(width, height) + readonly property bool insideDate: root.dateText !== "" && span > Theme.buttonHeightM * 2 && dialMetrics.advanceWidth <= span * 0.5 + readonly property bool sideDate: root.dateText !== "" && !insideDate && width - height >= dateMetrics.advanceWidth + Theme.spacingS + readonly property bool belowDate: root.dateText !== "" && !insideDate && !sideDate + readonly property real dialSize: belowDate ? Math.min(width, height - root.supportLine - Theme.spacingS) : span + readonly property real groupWidth: sideDate ? dialSize + Theme.spacingS + dateMetrics.advanceWidth : dialSize + readonly property real groupHeight: belowDate ? dialSize + Theme.spacingS + root.supportLine : dialSize + + DankAnalogClock { + id: dial + x: (face.width - face.groupWidth) / 2 + y: (face.height - face.groupHeight) / 2 + width: face.dialSize + height: face.dialSize + hours: systemClock.date.getHours() + minutes: systemClock.date.getMinutes() + seconds: systemClock.date.getSeconds() + showSeconds: root.showSeconds + showNumbers: root.options.numbers === true + numbersOutside: root.tinted + dateText: face.insideDate ? root.dateText : "" + color: root.tinted ? root.onAccentColor : root.accentColor + numberColor: root.accentColor + backgroundColor: root.tinted ? root.accentColor : root.chipColor + facePadding: 0 + } + + StyledText { + id: dateLabel + visible: face.sideDate || face.belowDate + x: face.sideDate ? dial.x + dial.width + Theme.spacingS : 0 + y: face.sideDate ? (face.height - height) / 2 : dial.y + dial.height + Theme.spacingS + width: face.sideDate ? dateMetrics.advanceWidth : face.width + height: root.supportLine + text: root.dateText + color: root.supportingColor + font.pixelSize: Theme.fontSizeMedium + font.weight: Theme.fontWeightMedium + minimumPixelSize: Theme.fontSizeSmall + fontSizeMode: Text.HorizontalFit + horizontalAlignment: face.sideDate ? Text.AlignLeft : Text.AlignHCenter + wrapMode: Text.NoWrap + elide: Text.ElideRight + } + + TextMetrics { + id: dateMetrics + font: dateLabel.font + text: root.dateText + } + + TextMetrics { + id: dialMetrics + font.family: dateLabel.font.family + font.pixelSize: Theme.fontSizeSmall + text: root.dateText + } } } diff --git a/quickshell/tests/qml/control-center-sizes.qml b/quickshell/tests/qml/control-center-sizes.qml index 1d716392c..7466b6801 100644 --- a/quickshell/tests/qml/control-center-sizes.qml +++ b/quickshell/tests/qml/control-center-sizes.qml @@ -21,7 +21,7 @@ ShellRoot { DC.Style.theme = Theme; DC.Style.settings = SettingsData; DC.I18n.backend = I18n; - SettingsData.animationSpeed = SettingsData.AnimationSpeed.None; + SettingsData.animationDuration = 0; Qt.callLater(tester.run); } @@ -73,6 +73,13 @@ ShellRoot { } } + Component { + id: detailComponent + CcDetailPage { + model: registry + } + } + Component { id: gridComponent CcTileGrid { @@ -110,6 +117,12 @@ ShellRoot { throw new Error(message); } + function settle() { + wait(0); + const surface = scene.Window.window; + check(!isPolishScheduled(surface) || waitForPolish(surface, 5000), "layout settled"); + } + function named(item, name) { if (item.objectName === name) return item; @@ -224,14 +237,12 @@ ShellRoot { Theme.fontScale = fontScale; for (const rtl of [false, true]) { tile.LayoutMirroring.enabled = rtl; - for (let columns = 1; columns <= 10; columns++) { - for (let rows = 1; rows <= 12; rows++) { - size(tile, columns, rows); - wait(0); - for (const name of ["tileIconBox", "tileTitle", "tileSubtitle", "tileExpandedContent"]) - inside(named(tile, name), tile, name + " " + columns + "x" + rows + " font " + fontScale); - actionBounds(tile, tile); - } + for (const [columns, rows] of [[1, 1], [2, 1], [1, 2], [2, 2], [3, 2], [4, 3], [10, 12]]) { + size(tile, columns, rows); + settle(); + for (const name of ["tileIconBox", "tileTitle", "tileSubtitle", "tileExpandedContent"]) + inside(named(tile, name), tile, name + " " + columns + "x" + rows + " font " + fontScale); + actionBounds(tile, tile); } } } @@ -239,7 +250,7 @@ ShellRoot { SettingsData.controlCenterIconScale = scale; for (const dimensions of [[1, 2], [2, 1], [2, 2], [2, 3]]) { size(tile, dimensions[0], dimensions[1]); - wait(0); + settle(); inside(named(tile, "tileIconBox"), tile, "scaled icon"); inside(named(tile, "tileTitle"), tile, "scaled title"); } @@ -248,7 +259,7 @@ ShellRoot { Theme.fontScale = 1; tile.LayoutMirroring.enabled = false; size(tile, 4, 3); - wait(0); + settle(); check(tile.expanded && tile.expandedItem !== null, "large tile exposes inline actions"); const inline = tile.expandedItem; check(inline.tile === tile && inline.columns === 4 && inline.rows === 3, "plugin content receives its tile context"); @@ -270,7 +281,7 @@ ShellRoot { const verticalSlider = sliderComponent.createObject(scene); size(verticalSlider, 1, 3); - wait(0); + settle(); check(verticalSlider.vertical, "portrait slider uses vertical track"); verticalSlider.slider.forceActiveFocus(); keyClick(Qt.Key_End); @@ -310,7 +321,7 @@ ShellRoot { h: dimensions[1] }, 10, 12); size(widget, supported.w, supported.h); - wait(0); + settle(); if (widget.slider) { check(widget.slider.width >= Theme.minimumTouchTargetSize, id + " retains a usable track at " + dimensions); inside(named(widget, "sliderTrackArea"), widget, id + " track"); @@ -327,7 +338,7 @@ ShellRoot { id: "colorPicker" }).createObject(scene); size(colorTile, 4, 6); - wait(0); + settle(); check(swatches(colorTile, colorTile) === 18, "taller color tiles show multiple rows of recent colors"); colorTile.destroy(); wait(0); @@ -344,6 +355,20 @@ ShellRoot { instance.destroy(); wait(0); } + const detail = detailComponent.createObject(scene, { + width: 600, + height: 400 + }); + detail.section = "doNotDisturb"; + settle(); + detail.section = ""; + settle(); + check(!detail.visible, "closed detail page hides"); + detail.width = 800; + settle(); + check(!detail.visible, "closed detail page stays hidden after the panel widens"); + detail.destroy(); + wait(0); console.log("FIXTURE_PASS control center sizes and actions"); } catch (error) { console.error("FIXTURE_FAIL " + error.message);