diff --git a/Components/HorizontalScrollBarTrack.qml b/Components/HorizontalScrollBarTrack.qml index 92185c4..35b3f34 100644 --- a/Components/HorizontalScrollBarTrack.qml +++ b/Components/HorizontalScrollBarTrack.qml @@ -2,55 +2,57 @@ import QtQuick import ZShell.Config import qs.Services -CustomClippingRect { +Item { id: track required property var scrollBar required property var mouseArea - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - implicitHeight: handle.implicitHeight - radius: Tokens.rounding.full - - CustomRect { - id: handle - - anchors.bottom: parent.bottom - color: Colors.palette.m3secondary - implicitWidth: track.scrollBar.width * track.scrollBar.effectiveSize - implicitHeight: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall - opacity: { - if (!track.scrollBar.enabled) - return 0; - if (track.scrollBar.size === 1) - return 0; - if (track.mouseArea.pressed) - return 1; - if (track.mouseArea.containsMouse) - return 0.8; - if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive) - return 0.6; - return 0; - } + ClipRect { radius: Tokens.rounding.full - x: track.scrollBar.reversed ? track.scrollBar.width * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.width * track.scrollBar.nonAnimY * track.scrollBar.travelScale + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + implicitHeight: handle.implicitHeight - Behavior on implicitHeight { - Anim {} - } - Behavior on opacity { - Anim { - type: Anim.DefaultEffects + CustomRect { + id: handle + + anchors.bottom: parent.bottom + color: Colors.palette.m3secondary + implicitWidth: track.scrollBar.width * track.scrollBar.effectiveSize + implicitHeight: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall + opacity: { + if (!track.scrollBar.enabled) + return 0; + if (track.scrollBar.size === 1) + return 0; + if (track.mouseArea.pressed) + return 1; + if (track.mouseArea.containsMouse) + return 0.8; + if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive) + return 0.6; + return 0; } - } + radius: Tokens.rounding.full + x: track.scrollBar.reversed ? track.scrollBar.width * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.width * track.scrollBar.nonAnimY * track.scrollBar.travelScale - MouseArea { - acceptedButtons: Qt.NoButton - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true + Behavior on implicitHeight { + Anim {} + } + Behavior on opacity { + Anim { + type: Anim.DefaultEffects + } + } + + MouseArea { + acceptedButtons: Qt.NoButton + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + } } } } diff --git a/Components/VerticalFadeFlickable.qml b/Components/VerticalFadeFlickable.qml index 099ecf7..c3c8337 100644 --- a/Components/VerticalFadeFlickable.qml +++ b/Components/VerticalFadeFlickable.qml @@ -30,7 +30,7 @@ CustomFlickable { type: Anim.SlowEffects } } - // layer.textureSize: Qt.size(width * dpr, height * dpr) + layer.textureSize: Qt.size(width * dpr, height * dpr) layer.effect: Mask { maskSource: mask diff --git a/Components/VerticalScrollBarTrack.qml b/Components/VerticalScrollBarTrack.qml index 62e7b5a..b5996d0 100644 --- a/Components/VerticalScrollBarTrack.qml +++ b/Components/VerticalScrollBarTrack.qml @@ -2,55 +2,57 @@ import QtQuick import ZShell.Config import qs.Services -CustomClippingRect { +Item { id: track required property var scrollBar required property var mouseArea - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.top: parent.top - implicitWidth: handle.implicitWidth - radius: Tokens.rounding.full - - CustomRect { - id: handle - + ClipRect { + anchors.bottom: parent.bottom anchors.right: parent.right - color: Colors.palette.m3secondary - implicitHeight: track.scrollBar.height * track.scrollBar.effectiveSize - implicitWidth: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall - opacity: { - if (!track.scrollBar.enabled) - return 0; - if (track.scrollBar.size === 1) - return 0; - if (track.mouseArea.pressed) - return 1; - if (track.mouseArea.containsMouse) - return 0.8; - if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive) - return 0.6; - return 0; - } + anchors.top: parent.top radius: Tokens.rounding.full - y: track.scrollBar.reversed ? track.scrollBar.height * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.height * track.scrollBar.nonAnimY * track.scrollBar.travelScale + implicitWidth: handle.implicitWidth - Behavior on implicitWidth { - Anim {} - } - Behavior on opacity { - Anim { - type: Anim.DefaultEffects + CustomRect { + id: handle + + anchors.right: parent.right + color: Colors.palette.m3secondary + implicitHeight: track.scrollBar.height * track.scrollBar.effectiveSize + implicitWidth: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall + opacity: { + if (!track.scrollBar.enabled) + return 0; + if (track.scrollBar.size === 1) + return 0; + if (track.mouseArea.pressed) + return 1; + if (track.mouseArea.containsMouse) + return 0.8; + if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive) + return 0.6; + return 0; } - } + radius: Tokens.rounding.full + y: track.scrollBar.reversed ? track.scrollBar.height * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.height * track.scrollBar.nonAnimY * track.scrollBar.travelScale - MouseArea { - acceptedButtons: Qt.NoButton - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true + Behavior on implicitWidth { + Anim {} + } + Behavior on opacity { + Anim { + type: Anim.DefaultEffects + } + } + + MouseArea { + acceptedButtons: Qt.NoButton + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + } } } } diff --git a/Drawers/Exclusions.qml b/Drawers/Exclusions.qml index 1af46fb..da31911 100644 --- a/Drawers/Exclusions.qml +++ b/Drawers/Exclusions.qml @@ -59,7 +59,6 @@ Scope { name: "Bar-Exclusion" screen: root.screen - mask: Region { - } + mask: Region {} } } diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index b6dce58..46fcda3 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -19,15 +19,11 @@ import ZShell.Config Item { id: root - required property Item bar - required property real borderThickness readonly property alias clipboard: clipboard readonly property alias dashboard: dashboard readonly property alias dashboardWrapper: dashboardWrapper readonly property alias dock: dock readonly property alias drawing: drawing - required property var drawingItem - required property EdgeGeometry geometry readonly property alias launcher: launcher readonly property alias notifications: notifications readonly property alias osd: osd @@ -36,14 +32,19 @@ Item { readonly property alias popoutsWrapper: popouts readonly property alias resources: resources readonly property alias resourcesWrapper: resourcesWrapper - required property ShellScreen screen - required property ScreenState screenState readonly property alias settings: settings readonly property alias settingsWrapper: settingsWrapper readonly property alias sidebar: sidebar readonly property alias toasts: toasts readonly property alias utilities: utilities + required property Item bar + required property real borderThickness + required property var drawingItem + required property EdgeGeometry geometry + required property ShellScreen screen + required property ScreenState screenState + anchors.bottomMargin: geometry.insetBottom(borderThickness) anchors.fill: parent anchors.leftMargin: geometry.insetLeft(borderThickness) diff --git a/Greeter/Center.qml b/Greeter/Center.qml index fc9a456..845b2fc 100644 --- a/Greeter/Center.qml +++ b/Greeter/Center.qml @@ -27,27 +27,21 @@ ColumnLayout { CustomText { Layout.alignment: Qt.AlignVCenter color: Colors.palette.m3secondary - font.bold: true - font.family: Config.appearance.font.family.clock - font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) + font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build() text: Time.hourStr } CustomText { Layout.alignment: Qt.AlignVCenter color: Colors.palette.m3primary - font.bold: true - font.family: Config.appearance.font.family.clock - font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) + font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build() text: ":" } CustomText { Layout.alignment: Qt.AlignVCenter color: Colors.palette.m3secondary - font.bold: true - font.family: Config.appearance.font.family.clock - font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) + font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build() text: Time.minuteStr } } @@ -56,13 +50,11 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter Layout.topMargin: -Tokens.padding.large * 2 color: Colors.palette.m3tertiary - font.bold: true - font.family: Config.appearance.font.family.mono - font.pointSize: Math.floor(Tokens.font.size.extraLarge * root.centerScale) + font: Tokens.font.title.builders.medium.weight(Font.DemiBold).build() text: Time.format("dddd, d MMMM yyyy") } - CustomClippingRect { + ClipRect { Layout.alignment: Qt.AlignHCenter Layout.topMargin: Tokens.spacing.largeIncreased * 2 color: Colors.tPalette.m3surfaceContainer @@ -73,7 +65,7 @@ ColumnLayout { MaterialIcon { anchors.centerIn: parent color: Colors.palette.m3onSurfaceVariant - font.pointSize: Math.floor(root.centerWidth / 4) + fontStyle: Tokens.font.icon.size(root.centerWidth / 4).build() text: "person" } @@ -88,9 +80,7 @@ ColumnLayout { CustomText { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3onSurfaceVariant - font.family: Config.appearance.font.family.mono - font.pointSize: Tokens.font.size.normal - font.weight: 600 + font: Tokens.font.body.large text: root.greeter.username visible: text.length > 0 } @@ -155,8 +145,7 @@ ColumnLayout { } Behavior on opacity { - Anim { - } + Anim {} } } @@ -191,7 +180,6 @@ ColumnLayout { anchors.centerIn: parent color: root.greeter.buffer && !root.greeter.launching ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface - font.weight: 500 text: root.greeter.launching ? "hourglass_top" : "arrow_forward" } } @@ -204,8 +192,7 @@ ColumnLayout { implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight) Behavior on implicitHeight { - Anim { - } + Anim {} } CustomText { @@ -245,12 +232,10 @@ ColumnLayout { wrapMode: Text.WrapAtWordBoundaryOrAnywhere Behavior on opacity { - Anim { - } + Anim {} } Behavior on scale { - Anim { - } + Anim {} } onMsgChanged: { @@ -292,8 +277,7 @@ ColumnLayout { anchors.left: parent.left anchors.right: parent.right color: isError ? Colors.palette.m3error : Colors.palette.m3primary - font.family: Config.appearance.font.family.mono - font.pointSize: Tokens.font.size.small + font: Tokens.font.mono.medium horizontalAlignment: Qt.AlignHCenter opacity: 0 scale: 0.7 diff --git a/Greeter/Components/CircularIndicator.qml b/Greeter/Components/CircularIndicator.qml index 1c9a97d..cf28beb 100644 --- a/Greeter/Components/CircularIndicator.qml +++ b/Greeter/Components/CircularIndicator.qml @@ -20,7 +20,7 @@ BusyIndicator { property int animState property color bgColor: Colors.palette.m3secondaryContainer property color fgColor: Colors.palette.m3primary - property real implicitSize: Tokens.font.size.normal * 3 + property real implicitSize: Tokens.font.body.medium.pointSize * 3 property real internalStrokeWidth: strokeWidth readonly property alias progress: manager.progress property real strokeWidth: Tokens.padding.extraSmall * 0.8 diff --git a/Greeter/Components/ClipRect.qml b/Greeter/Components/ClipRect.qml new file mode 100644 index 0000000..39ac012 --- /dev/null +++ b/Greeter/Components/ClipRect.qml @@ -0,0 +1,41 @@ +import QtQuick +import ZShell.Components + +Item { + id: root + + property real radius + property real topLeftRadius: radius + property real topRightRadius: radius + property real bottomRightRadius: radius + property real bottomLeftRadius: radius + property color color: "transparent" + default property alias contentData: contentItem.data + + Item { + id: contentItem + + anchors.fill: parent + } + + ShaderEffectSource { + id: source + + hideSource: true + sourceItem: contentItem + } + + RoundedMask { + anchors.fill: parent + source: source + topLeftRadius: root.topLeftRadius + topRightRadius: root.topRightRadius + bottomRightRadius: root.bottomRightRadius + bottomLeftRadius: root.bottomLeftRadius + color: root.color + } + + Behavior on color { + CAnim {} + } +} diff --git a/Greeter/Components/CustomFlickable.qml b/Greeter/Components/CustomFlickable.qml index 01a9652..1373d1e 100644 --- a/Greeter/Components/CustomFlickable.qml +++ b/Greeter/Components/CustomFlickable.qml @@ -1,13 +1,36 @@ import QtQuick +import qs.Services Flickable { id: root + property bool doneFakeFlick + + interactive: !ShellState.forActive().isDrawing maximumFlickVelocity: 3000 rebound: Transition { + onRunningChanged: { + if (!running && !root.doneFakeFlick) { + root.doneFakeFlick = true; + root.flick(1, 1); + root.flick(-1, -1); + Qt.callLater(() => root.cancelFlick()); + } + } + Anim { properties: "x,y" } } + + Timer { + interval: 10 + running: root.doneFakeFlick + + onTriggered: { + root.doneFakeFlick = false; + root.returnToBounds(); + } + } } diff --git a/Greeter/Components/CustomListView.qml b/Greeter/Components/CustomListView.qml index 51c7110..97936d3 100644 --- a/Greeter/Components/CustomListView.qml +++ b/Greeter/Components/CustomListView.qml @@ -1,13 +1,36 @@ import QtQuick +import qs.Services ListView { id: root + property bool doneFakeFlick + + interactive: !ShellState.forActive()?.isDrawing maximumFlickVelocity: 3000 rebound: Transition { + // onRunningChanged: { + // if (!running && !root.doneFakeFlick) { + // root.doneFakeFlick = true; + // root.flick(1, 1); + // root.flick(-1, -1); + // Qt.callLater(() => root.cancelFlick()); + // } + // } + Anim { properties: "x,y" + type: Anim.DefaultEffects } } + + // Timer { + // interval: 10 + // running: root.doneFakeFlick + // + // onTriggered: { + // root.doneFakeFlick = false; + // } + // } } diff --git a/Greeter/Components/CustomMouseArea.qml b/Greeter/Components/CustomMouseArea.qml index 6d52d16..0737476 100644 --- a/Greeter/Components/CustomMouseArea.qml +++ b/Greeter/Components/CustomMouseArea.qml @@ -4,6 +4,7 @@ MouseArea { property int scrollAccumulatedY: 0 function onWheel(event: WheelEvent): void { + event.accepted = false; } onWheel: event => { diff --git a/Greeter/Components/CustomRect.qml b/Greeter/Components/CustomRect.qml index 2f5da64..b163d99 100644 --- a/Greeter/Components/CustomRect.qml +++ b/Greeter/Components/CustomRect.qml @@ -6,7 +6,6 @@ Rectangle { color: "transparent" Behavior on color { - CAnim { - } + CAnim {} } } diff --git a/Greeter/Components/CustomText.qml b/Greeter/Components/CustomText.qml index abd4952..5445f5f 100644 --- a/Greeter/Components/CustomText.qml +++ b/Greeter/Components/CustomText.qml @@ -14,10 +14,9 @@ Text { property real animateTo: 1 color: Colors.palette.m3onSurface - font.family: Config.appearance.font.family.sans - font.pointSize: Tokens.font.size.normal + font: Tokens.font.body.small linkColor: Colors.palette.m3onPrimaryFixedVariant - renderType: Text.NativeRendering + renderType: Text.QtRendering textFormat: Text.PlainText Behavior on color { @@ -28,22 +27,25 @@ Text { enabled: root.animate SequentialAnimation { - Anim { + TAnim { + target: root to: root.animateFrom + type: Anim.FastEffects } PropertyAction { } - Anim { + TAnim { + target: root to: root.animateTo + type: Anim.DefaultEffects } } } - component Anim: NumberAnimation { + component TAnim: Anim { duration: root.animateDuration / 2 - easing.type: Easing.BezierSpline properties: root.animateProp.split(",").length > 1 ? root.animateProp : "" property: root.animateProp.split(",").length === 1 ? root.animateProp : "" target: root diff --git a/Greeter/Components/CustomTextField.qml b/Greeter/Components/CustomTextField.qml index c49e841..ab2ff06 100644 --- a/Greeter/Components/CustomTextField.qml +++ b/Greeter/Components/CustomTextField.qml @@ -1,76 +1,305 @@ pragma ComponentBehavior: Bound import QtQuick -import QtQuick.Controls +import QtQuick.Shapes import ZShell.Config import qs.Services -TextField { +TextFieldBase { id: root - background: null - color: Colors.palette.m3onSurface - cursorVisible: !readOnly - font.family: Config.appearance.font.family.sans - font.pointSize: Tokens.font.size.smaller - placeholderTextColor: Colors.palette.m3outline - renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering + enum TextFieldType { + Outlined, + Filled + } - Behavior on color { - CAnim { + readonly property int clampedRadius: Math.min(horizontalPadding, Math.min(width, height) / 2, radius) + readonly property string effectiveSupportingText: isError && errorText ? errorText : supportingText + readonly property int filledOffset: type === CustomTextField.Filled ? Tokens.spacing.small : 0 + readonly property int leadingOffset: leadingIcon ? leadingIconLoader.width + leadingIconLoader.anchors.leftMargin : 0 + readonly property real smallFontScale: smallFontSize / font.pointSize + readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Tokens.spacing.extraSmall : 0 + readonly property int trailingOffset: trailingIcon ? trailingIconLoader.width + trailingIconLoader.anchors.rightMargin : 0 + readonly property bool valid: !validate || (!text && emptyIsValid) || (validate instanceof RegExp ? validate.test(text) : !!validate(text)) + + property int horizontalPadding: Tokens.padding.large + property int verticalPadding: Tokens.padding.large + + property int radius: Tokens.rounding.small + + property string supportingText + property string trailingIcon + property int smallFontSize: Tokens.font.label.small.pointSize + + property int type: CustomTextField.Outlined + property var validate // Regex or function + property bool emptyIsValid: true + property string errorText + property bool isError + property string leadingIcon + + bottomPadding: verticalPadding + supportingTextOffset - filledOffset + leftPadding: horizontalPadding + leadingOffset + rightPadding: horizontalPadding + trailingOffset + topPadding: verticalPadding + filledOffset + + background: Loader { + anchors.bottomMargin: root.supportingTextOffset + anchors.fill: parent + sourceComponent: root.type === CustomTextField.Filled ? filledComp : outlineComp + + StateLayer { + id: stateLayer + + cursorShape: Qt.IBeamCursor + enabled: !root.activeFocus + manualPressOverride: tapHandler.pressed + radius: root.type === CustomTextField.Outlined ? root.clampedRadius : 0 + topLeftRadius: root.clampedRadius + topRightRadius: root.clampedRadius + + onClicked: root.focus = true } } - cursorDelegate: CustomRect { - id: cursor - property bool disableBlink + onEditingFinished: { + if (!valid) + isError = true; + } + onPressed: { + if (stateLayer.enabled) + stateLayer.press(stateLayer.mouseX, stateLayer.mouseY); + } + onTextEdited: { + if (isError) + isError = false; + } - color: Colors.palette.m3primary - implicitWidth: 2 - radius: Tokens.rounding.medium + Item { + id: contentWrapper - Behavior on opacity { - Anim { - duration: Tokens.anim.durations.small - } - } + anchors.bottomMargin: root.supportingTextOffset + anchors.fill: parent - Connections { - function onCursorPositionChanged(): void { - if (root.activeFocus && root.cursorVisible) { - cursor.opacity = 1; - cursor.disableBlink = true; - enableBlink.restart(); + CustomText { + id: placeholder + + anchors.left: parent.left + anchors.leftMargin: root.leftPadding + anchors.topMargin: Tokens.padding.extraSmall + anchors.verticalCenter: parent.verticalCenter + color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : root.text ? Colors.palette.m3outline : root.placeholderTextColor) + font.family: root.font.family + font.pointSize: root.font.pointSize + font.variableAxes: root.font.variableAxes + font.weight: root.font.weight + renderType: Text.QtRendering + text: root.placeholderText + + states: [ + State { + name: "smallOutlined" + when: root.type === CustomTextField.Outlined && (root.activeFocus || root.text) + + PropertyChanges { + placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + placeholder.scale: root.smallFontScale + } + + AnchorChanges { + anchors.verticalCenter: contentWrapper.top + target: placeholder + } + }, + State { + name: "smallFilled" + when: root.type === CustomTextField.Filled && (root.activeFocus || root.text) + + PropertyChanges { + placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + root.leadingOffset + placeholder.scale: root.smallFontScale + } + + AnchorChanges { + anchors.top: contentWrapper.top + anchors.verticalCenter: undefined + target: placeholder + } + } + ] + transitions: Transition { + Anim { + properties: "scale,leftMargin" + type: Anim.DefaultEffects + } + + AnchorAnim { + duration: Tokens.anim.durations.expressiveDefaultEffects + easing: Tokens.anim.expressiveDefaultEffects } } - - target: root } - Timer { - id: enableBlink + Loader { + id: leadingIconLoader - interval: 100 + active: root.leadingIcon + anchors.left: parent.left + anchors.leftMargin: Tokens.padding.small + anchors.verticalCenter: parent.verticalCenter - onTriggered: cursor.disableBlink = false + sourceComponent: MaterialIcon { + color: Colors.palette.m3onSurfaceVariant + text: root.leadingIcon + fontStyle: Tokens.font.icon.builders.medium.scale(0.9).build() + } } - Timer { - interval: 500 - repeat: true - running: root.activeFocus && root.cursorVisible && !cursor.disableBlink - triggeredOnStart: true + Loader { + id: trailingIconLoader - onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1 - } + active: root.trailingIcon + anchors.right: parent.right + anchors.rightMargin: Tokens.padding.small + anchors.verticalCenter: parent.verticalCenter - Binding { - cursor.opacity: 0 - when: !root.activeFocus || !root.cursorVisible + sourceComponent: MaterialIcon { + color: Colors.palette.m3onSurfaceVariant + text: root.trailingIcon + fontStyle: Tokens.font.icon.builders.medium.scale(0.9).build() + } } } - Behavior on placeholderTextColor { - CAnim { + + Loader { + id: supportingTextLoader + + active: root.effectiveSupportingText + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.leftMargin: root.horizontalPadding + + sourceComponent: CustomText { + color: root.isError ? Colors.palette.m3error : Colors.palette.m3onSurfaceVariant + font: Tokens.font.label.small + text: root.effectiveSupportingText + } + } + + TapHandler { + id: tapHandler + } + + Component { + id: outlineComp + + Shape { + id: bg + + asynchronous: true + preferredRendererType: Shape.CurveRenderer + + ShapePath { + id: path + + readonly property real inset: strokeWidth / 2 + readonly property real outlineGap: placeholder.width * root.smallFontScale + Tokens.spacing.small * 2 + property real outlineGapScale: root.activeFocus || root.text ? 1 : 0 + + capStyle: ShapePath.RoundCap + fillColor: "transparent" + startX: path.inset + root.horizontalPadding - root.clampedRadius + path.outlineGap * (1 - path.outlineGapScale) / 2 + path.outlineGap * path.outlineGapScale + startY: path.inset + strokeColor: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline) + strokeWidth: root.activeFocus ? 2 : 1 + + Behavior on outlineGapScale { + Anim { + type: Anim.DefaultEffects + } + } + Behavior on strokeColor { + CAnim {} + } + Behavior on strokeWidth { + Anim {} + } + + PathLine { + x: bg.width - path.inset - root.clampedRadius + y: path.inset + } + + PathArc { + radiusX: root.clampedRadius + radiusY: root.clampedRadius + x: bg.width - path.inset + y: path.inset + root.clampedRadius + } + + PathLine { + x: bg.width - path.inset + y: bg.height - path.inset - root.clampedRadius + } + + PathArc { + radiusX: root.clampedRadius + radiusY: root.clampedRadius + x: bg.width - path.inset - root.clampedRadius + y: bg.height - path.inset + } + + PathLine { + x: path.inset + root.clampedRadius + y: bg.height - path.inset + } + + PathArc { + radiusX: root.clampedRadius + radiusY: root.clampedRadius + x: path.inset + y: bg.height - path.inset - root.clampedRadius + } + + PathLine { + x: path.inset + y: path.inset + root.clampedRadius + } + + PathArc { + radiusX: root.clampedRadius + radiusY: root.clampedRadius + x: path.inset + root.clampedRadius + y: path.inset + } + + PathLine { + x: path.inset + root.horizontalPadding - root.clampedRadius / 2 + path.outlineGap * (1 - path.outlineGapScale) / 2 + y: path.inset + } + } + } + } + + Component { + id: filledComp + + CustomRect { + color: root.activeFocus ? Colors.tPalette.m3surfaceContainerHighest : Colors.tPalette.m3surfaceContainerHigh + topLeftRadius: root.clampedRadius + topRightRadius: root.clampedRadius + + CustomRect { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline) + implicitHeight: root.activeFocus ? 2 : 1 + + Behavior on implicitHeight { + Anim {} + } + } } } } diff --git a/Greeter/Components/CustomTextInput.qml b/Greeter/Components/CustomTextInput.qml index 42c6ead6..7f6e0d2 100644 --- a/Greeter/Components/CustomTextInput.qml +++ b/Greeter/Components/CustomTextInput.qml @@ -1,15 +1,16 @@ import QtQuick +import QtQuick.Controls import ZShell.Config import qs.Services TextInput { renderType: Text.NativeRendering selectedTextColor: Colors.palette.m3onSecondaryContainer - selectionColor: Colors.tPalette.m3onSecondaryContainer + selectionColor: Colors.tPalette.colSecondaryContainer font { family: Config.appearance?.font.family.sans ?? "sans-serif" hintingPreference: Font.PreferFullHinting - pixelSize: Tokens?.font.size.normal ?? 15 + pixelSize: Config.appearance?.font.size.normal ?? 15 } } diff --git a/Greeter/Components/FadeImage.qml b/Greeter/Components/FadeImage.qml new file mode 100644 index 0000000..79617aa --- /dev/null +++ b/Greeter/Components/FadeImage.qml @@ -0,0 +1,79 @@ +import QtQuick +import Quickshell +import ZShell.Config + +Image { + id: root + + property int fadeInAnim: Anim.DefaultEffects + property int fadeInLargeAnim: Anim.StandardLarge + property int fadeOutAnim: Anim.FastEffects + property bool fadingOut + property bool hadPrevious + property bool preventInit + + function maybeStartInAnim(): void { + if (!preventInit && !opacityInAnim.running && status === Image.Ready) { + opacityInAnim.type = hadPrevious ? fadeInAnim : fadeInLargeAnim; + opacityInAnim.start(); + } + } + + asynchronous: true + fillMode: Image.PreserveAspectCrop + opacity: 0 + retainWhileLoading: true + sourceSize: { + const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1; + return Qt.size(width * dpr, height * dpr); + } + + Anim on opacity { + id: opacityInAnim + + running: false + to: 1 + } + Behavior on source { + SequentialAnimation { + ScriptAction { + script: opacityInAnim.stop() + } + + PropertyAction { + property: "fadingOut" + target: root + value: true + } + + Anim { + property: "opacity" + target: root + to: 0 + type: root.fadeOutAnim + } + + PropertyAction { + property: "fadingOut" + target: root + value: false + } + + PropertyAction { + property: "hadPrevious" + target: root + value: root.source + } + + PropertyAction { + } + + ScriptAction { + script: root.maybeStartInAnim() + } + } + } + + onPreventInitChanged: maybeStartInAnim() + onStatusChanged: maybeStartInAnim() +} diff --git a/Greeter/Components/LoadingIndicator.qml b/Greeter/Components/LoadingIndicator.qml new file mode 100644 index 0000000..2e1132a --- /dev/null +++ b/Greeter/Components/LoadingIndicator.qml @@ -0,0 +1,115 @@ +import QtQuick +import Quickshell +import M3Shapes +import ZShell.Config +import qs.Services + +MaterialShape { + id: root + + property bool animated: true + property real cRotation + property bool containsIcon + property real dampingRatio: 0.6 + property real lRotation + property int morphAnimRotation: 60 + property real morphScale: 0.14 + property alias rotateAnimDuration: rotateAnim.duration + property int shapeIndex + property list shapes: { + if (containsIcon) + return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval]; + return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pentagon, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval]; + } + readonly property real springDuration: { + const wn = Math.sqrt(stiffness); + const r = -dampingRatio * wn; + const c = 1 / Math.sqrt(1 - dampingRatio * dampingRatio); + return Math.log(visibilityThreshold / c) / r; + } + readonly property real springMaxVelocity: { + const wn = Math.sqrt(stiffness); + const factor = Math.exp(-z * Math.acos(z) / Math.sqrt(1 - z * z)); + return wn * factor; + } + property bool springSettled: true + property real stiffness: 180 + property real thisLRotation + property real visibilityThreshold: 0.075 + + function spring(t: real): var { + const wn = Math.sqrt(stiffness); + const za = dampingRatio * wn; + + const wd = wn * Math.sqrt(1 - dampingRatio * dampingRatio); + const r = za / wd; + const pos = 1 - Math.exp(-za * t) * (Math.cos(wd * t) + r * Math.sin(wd * t)); + const vel = Math.exp(-za * t) * (wn * wn / wd) * Math.sin(wd * t); + + return [pos, vel]; + } + + color: Colors.palette.m3primary + implicitSize: 38 + toShape: shapes[0] + + RotationAnimation on cRotation { + id: rotateAnim + + duration: 4666 + easing.type: Easing.Linear + from: 0 + loops: Animation.Infinite + running: root.animated + to: 360 + } + Behavior on color { + CAnim { + } + } + + ElapsedTimer { + id: timer + } + + FrameAnimation { + running: root.animated && !root.springSettled + + onTriggered: { + const t = timer.elapsed(); + + if (t >= root.springDuration) { + root.springSettled = true; + } else { + const [pos, vel] = root.spring(t); + root.morphProgress = Math.min(1, pos); // Overshooting the morph looks weird + root.thisLRotation = pos * root.morphAnimRotation; + root.scale = 1 + vel * root.morphScale / root.springMaxVelocity; + } + } + } + + Timer { + interval: 650 + repeat: true + running: root.animated + triggeredOnStart: true + + onTriggered: { + root.beginBatchUpdate(); + root.fromShape = root.toShape; + root.shapeIndex = (root.shapeIndex + 1) % root.shapes.length; + root.toShape = root.shapes[root.shapeIndex]; + root.morphProgress = 0; + + root.rotation = root.rotation; + root.lRotation = (root.lRotation + root.thisLRotation) % 360; + root.thisLRotation = 0; + root.rotation = Qt.binding(() => root.cRotation + root.lRotation + root.thisLRotation); + + root.springSettled = false; + timer.restart(); + root.endBatchUpdate(); + } + } +} diff --git a/Greeter/Components/MaterialIcon.qml b/Greeter/Components/MaterialIcon.qml index c518426..73ca9d9 100644 --- a/Greeter/Components/MaterialIcon.qml +++ b/Greeter/Components/MaterialIcon.qml @@ -1,16 +1,14 @@ +import QtQuick import ZShell.Config import qs.Services CustomText { - property real fill - property int grade: Colors.light ? 0 : -25 + id: root - font.family: "Material Symbols Rounded" - font.pointSize: Tokens.font.size.larger - font.variableAxes: ({ - FILL: fill.toFixed(1), - GRAD: grade, - opsz: fontInfo.pixelSize, - wght: fontInfo.weight - }) + property real fill: 0 + property int grade: Colors.light ? 0 : -25 + property font fontStyle: Tokens.font.icon.small + + renderType: Text.NativeRendering + font: Tokens.font.icon.size(fontStyle.pointSize).weight(fontStyle.weight).vaxes(fontStyle.variableAxes).fill(fill.toFixed(1)).grade(grade).build() } diff --git a/Greeter/Components/StateLayer.qml b/Greeter/Components/StateLayer.qml index 2596748..2585962 100644 --- a/Greeter/Components/StateLayer.qml +++ b/Greeter/Components/StateLayer.qml @@ -1,8 +1,6 @@ import QtQuick import QtQuick.Shapes import ZShell -import ZShell.Components -import qs.Helpers import ZShell.Config import qs.Services @@ -13,7 +11,6 @@ MouseArea { property alias bottomRightRadius: base.bottomRightRadius property real circleRadius property alias color: base.color - property bool disabled readonly property real endRadius: { const d1 = distSq(0, 0); const d2 = distSq(width, 0); @@ -22,6 +19,7 @@ MouseArea { return (Math.sqrt(Math.max(d1, d2, d3, d4)) + (shapeMorph ? 24 : 0)) * 1.3; } property real endRadiusAtPress + property bool manualHoverOverride property bool manualPressOverride property real pressX: width / 2 property real pressY: height / 2 @@ -29,7 +27,7 @@ MouseArea { readonly property alias rect: base property bool shapeMorph property bool showHoverBackground: true - property real stateOpacity: containsMouse ? 0.08 : 0 + property real stateOpacity: containsMouse || manualHoverOverride ? 0.08 : 0 property alias topLeftRadius: base.topLeftRadius property alias topRightRadius: base.topRightRadius @@ -52,8 +50,8 @@ MouseArea { } anchors.fill: parent - cursorShape: disabled ? undefined : Qt.PointingHandCursor - enabled: !disabled + cursorShape: !enabled ? undefined : Qt.PointingHandCursor + enabled: parent.enabled hoverEnabled: true Behavior on stateOpacity { @@ -100,13 +98,13 @@ MouseArea { id: base anchors.fill: parent - bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0 - bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0 color: Colors.palette.m3onSurface opacity: root.stateOpacity // Pick up radius from parent if it has one (parent can be anything with radius props) // qmllint disable missing-property radius: root.parent?.radius ?? 0 + bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0 + bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0 topLeftRadius: root.parent?.topLeftRadius ?? radius ?? 0 topRightRadius: root.parent?.topRightRadius ?? radius ?? 0 // qmllint enable missing-property diff --git a/Greeter/Content.qml b/Greeter/Content.qml index f873dde..78104b1 100644 --- a/Greeter/Content.qml +++ b/Greeter/Content.qml @@ -13,34 +13,16 @@ RowLayout { spacing: Tokens.spacing.largeIncreased * 2 - ColumnLayout { + CustomRect { + Layout.fillHeight: true Layout.fillWidth: true - spacing: Tokens.spacing.medium + topLeftRadius: Tokens.rounding.largeIncreased + bottomLeftRadius: Tokens.rounding.largeIncreased + color: Colors.tPalette.m3surfaceContainer + radius: Tokens.rounding.small - CustomRect { - Layout.fillWidth: true - color: Colors.tPalette.m3surfaceContainer - implicitHeight: weather.implicitHeight - radius: Tokens.rounding.small - topLeftRadius: Tokens.rounding.largeIncreased - - WeatherInfo { - id: weather - - rootHeight: root.height - } - } - - CustomClippingRect { - Layout.fillHeight: true - Layout.fillWidth: true - bottomLeftRadius: Tokens.rounding.largeIncreased - color: Colors.tPalette.m3surfaceContainer - radius: Tokens.rounding.small - - UserDock { - greeter: root.greeter - } + UserDock { + greeter: root.greeter } } @@ -49,21 +31,16 @@ RowLayout { screenHeight: root.screenHeight } - ColumnLayout { + CustomRect { + Layout.fillHeight: true Layout.fillWidth: true - spacing: Tokens.spacing.medium + bottomRightRadius: Tokens.rounding.largeIncreased + color: Colors.tPalette.m3surfaceContainer + radius: Tokens.rounding.small + topRightRadius: Tokens.rounding.largeIncreased - CustomRect { - Layout.fillHeight: true - Layout.fillWidth: true - bottomRightRadius: Tokens.rounding.largeIncreased - color: Colors.tPalette.m3surfaceContainer - radius: Tokens.rounding.small - topRightRadius: Tokens.rounding.largeIncreased - - SessionDock { - greeter: root.greeter - } + SessionDock { + greeter: root.greeter } } } diff --git a/Greeter/GreeterSurface.qml b/Greeter/GreeterSurface.qml index ab9ec0a..7f189ab 100644 --- a/Greeter/GreeterSurface.qml +++ b/Greeter/GreeterSurface.qml @@ -134,8 +134,7 @@ Scope { id: lockIcon anchors.centerIn: parent - font.bold: true - font.pointSize: Tokens.font.size.extraLarge * 4 + fontStyle: Tokens.font.icon.builders.extraLarge.size(Tokens.font.icon.extraLarge.pointSize * 3).build() text: "lock" } diff --git a/Greeter/InputField.qml b/Greeter/InputField.qml index 2246375..89b46ab 100644 --- a/Greeter/InputField.qml +++ b/Greeter/InputField.qml @@ -39,8 +39,7 @@ Item { anchors.centerIn: parent animate: true color: root.greeter.launching ? Colors.palette.m3secondary : Colors.palette.m3outline - font.family: Config.appearance.font.family.mono - font.pointSize: Tokens.font.size.normal + font: Tokens.font.mono.medium opacity: root.buffer ? 0 : 1 text: { if (root.greeter.launching) @@ -51,8 +50,7 @@ Item { } Behavior on opacity { - Anim { - } + Anim {} } } @@ -64,15 +62,13 @@ Item { anchors.verticalCenter: parent.verticalCenter color: Colors.palette.m3onSurface elide: Text.ElideLeft - font.family: Config.appearance.font.family.mono - font.pointSize: Tokens.font.size.normal + font: Tokens.font.mono.medium horizontalAlignment: Qt.AlignHCenter opacity: root.greeter.echoResponse && root.buffer ? 1 : 0 text: root.buffer Behavior on opacity { - Anim { - } + Anim {} } } @@ -89,7 +85,7 @@ Item { anchors.centerIn: parent anchors.horizontalCenterOffset: implicitWidth > root.width ? -(implicitWidth - root.width) / 2 : 0 - implicitHeight: Tokens.font.size.normal + implicitHeight: Tokens.font.body.medium implicitWidth: fullWidth interactive: false opacity: root.greeter.echoResponse ? 0 : 1 @@ -107,8 +103,7 @@ Item { scale: 0 Behavior on opacity { - Anim { - } + Anim {} } Behavior on scale { Anim { @@ -156,15 +151,13 @@ Item { Behavior on implicitWidth { id: imWidthBehavior - Anim { - } + Anim {} } model: ScriptModel { values: root.buffer.split("") } Behavior on opacity { - Anim { - } + Anim {} } } } diff --git a/Greeter/SessionDock.qml b/Greeter/SessionDock.qml index 066a6c1..a1b2b72 100644 --- a/Greeter/SessionDock.qml +++ b/Greeter/SessionDock.qml @@ -13,22 +13,19 @@ ColumnLayout { anchors.fill: parent anchors.margins: Tokens.padding.large - spacing: Tokens.spacing.small + spacing: Tokens.spacing.large CustomText { Layout.fillWidth: true color: Colors.palette.m3outline elide: Text.ElideRight - font.family: Config.appearance.font.family.mono - font.weight: 500 + font: Tokens.font.mono.builders.small.weight(Font.Medium).build() text: root.greeter.sessions.length > 0 ? qsTr("%1 session%2").arg(root.greeter.sessions.length).arg(root.greeter.sessions.length === 1 ? "" : "s") : qsTr("Sessions") } - CustomClippingRect { + Item { Layout.fillHeight: true Layout.fillWidth: true - color: "transparent" - radius: Tokens.rounding.small Loader { active: opacity > 0 @@ -46,16 +43,14 @@ ColumnLayout { MaterialIcon { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant - font.pointSize: Tokens.font.size.extraLarge * 2 + fontStyle: Tokens.font.icon.large text: "desktop_windows" } CustomText { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant - font.family: Config.appearance.font.family.mono - font.pointSize: Tokens.font.size.large - font.weight: 500 + font: Tokens.font.headline.builders.small.width(90).build() text: qsTr("No Sessions Found") } } @@ -68,6 +63,7 @@ ColumnLayout { clip: true currentIndex: root.greeter.sessionIndex highlightFollowsCurrentItem: false + boundsBehavior: ListView.StopAtBounds model: root.greeter.sessions spacing: Tokens.spacing.small @@ -80,7 +76,7 @@ ColumnLayout { anchors.left: parent?.left anchors.right: parent?.right implicitHeight: row.implicitHeight + Tokens.padding.small * 2 - radius: Tokens.rounding.medium - Tokens.padding.small + radius: Tokens.rounding.large StateLayer { onClicked: { @@ -97,7 +93,7 @@ ColumnLayout { MaterialIcon { color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurfaceVariant - font.pointSize: Tokens.font.size.extraLarge + fontStyle: Tokens.font.icon.extraLarge text: modelData.kind === "x11" ? "tv" : "desktop_windows" } @@ -109,8 +105,7 @@ ColumnLayout { Layout.fillWidth: true color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface elide: Text.ElideRight - font.pointSize: Tokens.font.size.normal - font.weight: 600 + font: Tokens.font.body.builders.medium.weight(Font.Bold).build() text: modelData.name } @@ -118,8 +113,7 @@ ColumnLayout { Layout.fillWidth: true color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimaryFixedVariant : Colors.palette.m3onSurfaceVariant elide: Text.ElideRight - font.family: Config.appearance.font.family.mono - font.pointSize: Tokens.font.size.small + font: Tokens.font.mono.small text: modelData.kind } } @@ -129,7 +123,7 @@ ColumnLayout { color: Colors.palette.m3primary implicitHeight: sessions.currentItem?.implicitHeight ?? 0 implicitWidth: sessions.width - radius: Tokens.rounding.medium - Tokens.padding.small + radius: Tokens.rounding.large y: sessions.currentItem?.y ?? 0 Behavior on y { diff --git a/Greeter/UserDock.qml b/Greeter/UserDock.qml index b53354c..d8d3085 100644 --- a/Greeter/UserDock.qml +++ b/Greeter/UserDock.qml @@ -14,22 +14,19 @@ ColumnLayout { anchors.fill: parent anchors.margins: Tokens.padding.large - spacing: Tokens.spacing.small + spacing: Tokens.spacing.large CustomText { Layout.fillWidth: true color: Colors.palette.m3outline elide: Text.ElideRight - font.family: Config.appearance.font.family.mono - font.weight: 500 + font: Tokens.font.mono.builders.small.weight(Font.Medium).build() text: root.greeter.users.length > 0 ? qsTr("%1 user%2").arg(root.greeter.users.length).arg(root.greeter.users.length === 1 ? "" : "s") : qsTr("Users") } - CustomClippingRect { + Item { Layout.fillHeight: true Layout.fillWidth: true - color: "transparent" - radius: Tokens.rounding.small Loader { active: opacity > 0 @@ -48,16 +45,14 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant fill: 1 - font.pointSize: Tokens.font.size.extraLarge * 2 + fontStyle: Tokens.font.icon.large text: "account_circle" } CustomText { Layout.alignment: Qt.AlignHCenter color: Colors.palette.m3outlineVariant - font.family: Config.appearance.font.family.mono - font.pointSize: Tokens.font.size.large - font.weight: 500 + font: Tokens.font.headline.builders.small.width(90).build() text: qsTr("No Users Found") } } @@ -70,6 +65,7 @@ ColumnLayout { clip: true currentIndex: root.greeter.selectedUser ? root.greeter.users.indexOf(root.greeter.selectedUser) : -1 highlightFollowsCurrentItem: false + boundsBehavior: ListView.StopAtBounds model: root.greeter.users spacing: Tokens.spacing.small @@ -82,7 +78,7 @@ ColumnLayout { anchors.left: parent?.left anchors.right: parent?.right implicitHeight: row.implicitHeight + Tokens.padding.small * 2 - radius: Tokens.rounding.medium - Tokens.padding.small + radius: Tokens.rounding.large StateLayer { onClicked: { @@ -97,7 +93,7 @@ ColumnLayout { anchors.margins: Tokens.padding.small spacing: Tokens.spacing.medium - CustomClippingRect { + ClipRect { Layout.preferredHeight: 50 Layout.preferredWidth: 50 radius: Tokens.rounding.full @@ -106,7 +102,7 @@ ColumnLayout { anchors.centerIn: parent color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurfaceVariant fill: 1 - font.pointSize: Tokens.font.size.extraLarge + fontStyle: Tokens.font.icon.extraLarge text: modelData.kind === "x11" ? "tv" : "account_circle" } @@ -124,8 +120,7 @@ ColumnLayout { Layout.fillWidth: true color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface elide: Text.ElideRight - font.pointSize: Tokens.font.size.normal - font.weight: 600 + font: Tokens.font.body.builders.medium.weight(Font.Bold).build() text: modelData.username } } @@ -135,7 +130,7 @@ ColumnLayout { color: Colors.palette.m3primary implicitHeight: users.currentItem?.implicitHeight ?? 0 implicitWidth: users.width - radius: Tokens.rounding.medium - Tokens.padding.small + radius: Tokens.rounding.large y: users.currentItem?.y ?? 0 Behavior on y { diff --git a/Greeter/WeatherInfo.qml b/Greeter/WeatherInfo.qml deleted file mode 100644 index 60cda3a..0000000 --- a/Greeter/WeatherInfo.qml +++ /dev/null @@ -1,171 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import ZShell.Config -import qs.Components -import qs.Helpers -import qs.Services - -ColumnLayout { - id: root - - required property int rootHeight - - anchors.left: parent.left - anchors.margins: Tokens.padding.large * 2 - anchors.right: parent.right - spacing: Tokens.spacing.small - - Loader { - Layout.alignment: Qt.AlignHCenter - Layout.bottomMargin: -Tokens.padding.large - Layout.topMargin: Tokens.padding.large * 2 - active: root.rootHeight > 610 - visible: active - - sourceComponent: CustomText { - color: Colors.palette.m3primary - font.pointSize: Tokens.font.size.extraLarge - font.weight: 500 - text: qsTr("Weather") - } - } - - RowLayout { - Layout.fillWidth: true - spacing: Tokens.spacing.largeIncreased - - MaterialIcon { - animate: true - color: Colors.palette.m3secondary - font.pointSize: Tokens.font.size.extraLarge * 2.5 - text: Weather.icon - } - - ColumnLayout { - spacing: Tokens.spacing.small - - CustomText { - Layout.fillWidth: true - animate: true - color: Colors.palette.m3secondary - elide: Text.ElideRight - font.pointSize: Tokens.font.size.large - font.weight: 500 - text: Weather.description - } - - CustomText { - Layout.fillWidth: true - animate: true - color: Colors.palette.m3onSurfaceVariant - elide: Text.ElideRight - font.pointSize: Tokens.font.size.normal - text: qsTr("Humidity: %1%").arg(Weather.humidity) - } - } - - Loader { - Layout.rightMargin: Tokens.padding.small - active: root.width > 400 - visible: active - - sourceComponent: ColumnLayout { - spacing: Tokens.spacing.small - - CustomText { - Layout.fillWidth: true - animate: true - color: Colors.palette.m3primary - elide: Text.ElideLeft - font.pointSize: Tokens.font.size.extraLarge - font.weight: 500 - horizontalAlignment: Text.AlignRight - text: Weather.temp - } - - CustomText { - Layout.fillWidth: true - animate: true - color: Colors.palette.m3outline - elide: Text.ElideLeft - font.pointSize: Tokens.font.size.smaller - horizontalAlignment: Text.AlignRight - text: qsTr("Feels like: %1").arg(Weather.feelsLike) - } - } - } - } - - Loader { - id: forecastLoader - - Layout.bottomMargin: Tokens.padding.large * 2 - Layout.fillWidth: true - Layout.topMargin: Tokens.spacing.small - active: root.rootHeight > 820 - visible: active - - sourceComponent: RowLayout { - spacing: Tokens.spacing.largeIncreased - - Repeater { - model: { - const forecast = Weather.hourlyForecast; - const count = root.width < 320 ? 3 : root.width < 400 ? 4 : 5; - if (!forecast) - return Array.from({ - length: count - }, () => null); - - const start = Math.max(0, Weather.currentHourIndex); - return forecast.slice(start, start + count); - } - - ColumnLayout { - id: forecastHour - - required property var modelData - - Layout.fillWidth: true - spacing: Tokens.spacing.small - - CustomText { - Layout.fillWidth: true - color: Colors.palette.m3outline - font.pointSize: Tokens.font.size.larger - horizontalAlignment: Text.AlignHCenter - text: { - const hour = forecastHour.modelData?.hour ?? 0; - return hour > 12 ? `${(hour - 12).toString().padStart(2, "0")} PM` : `${hour.toString().padStart(2, "0")} AM`; - } - } - - MaterialIcon { - Layout.alignment: Qt.AlignHCenter - font.pointSize: Tokens.font.size.extraLarge * 1.5 - font.weight: 500 - text: forecastHour.modelData?.icon ?? "cloud_alert" - } - - CustomText { - Layout.alignment: Qt.AlignHCenter - color: Colors.palette.m3secondary - font.pointSize: Tokens.font.size.larger - text: Config.services.useFahrenheit ? `${forecastHour.modelData?.tempF ?? 0}°F` : `${forecastHour.modelData?.tempC ?? 0}°C` - } - } - } - } - } - - Timer { - interval: 900000 // 15 minutes - repeat: true - running: true - triggeredOnStart: true - - onTriggered: Weather.reload() - } -} diff --git a/Modules/Bar/Border.qml b/Modules/Bar/Border.qml deleted file mode 100644 index 95503f6..0000000 --- a/Modules/Bar/Border.qml +++ /dev/null @@ -1,49 +0,0 @@ -pragma ComponentBehavior: Bound - -import Quickshell -import QtQuick -import QtQuick.Effects -import ZShell.Config -import qs.Components -import qs.Services - -Item { - id: root - - required property Item bar - required property ScreenState screenState - - anchors.fill: parent - - CustomRect { - anchors.fill: parent - anchors.margins: -1 - color: Colors.palette.m3surface - layer.enabled: true - - layer.effect: MultiEffect { - maskEnabled: true - maskInverted: true - maskSource: mask - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - } - - Item { - id: mask - - anchors.fill: parent - layer.enabled: true - visible: false - - Rectangle { - anchors.fill: parent - anchors.margins: Config.bar.border + 1 - anchors.topMargin: root.bar.implicitHeight + 1 - radius: Config.bar.border > 0 ? Config.bar.rounding : 0 - topLeftRadius: Config.bar.rounding - topRightRadius: Config.bar.rounding - } - } -} diff --git a/Modules/Bar/Popouts/AudioPopout.qml b/Modules/Bar/Popouts/AudioPopout.qml index c218e72..023bd68 100644 --- a/Modules/Bar/Popouts/AudioPopout.qml +++ b/Modules/Bar/Popouts/AudioPopout.qml @@ -134,7 +134,7 @@ Item { node: Audio.source } - CustomClippingRect { + ClipRect { anchors.fill: parent radius: parent.radius @@ -249,7 +249,7 @@ Item { node: appBox.modelData } - CustomClippingRect { + ClipRect { anchors.fill: parent radius: parent.radius diff --git a/Modules/Clipboard/Content.qml b/Modules/Clipboard/Content.qml index f4683c6..8fd5c62 100644 --- a/Modules/Clipboard/Content.qml +++ b/Modules/Clipboard/Content.qml @@ -25,7 +25,7 @@ Item { searchField.forceActiveFocus(); } - CustomClippingRect { + ClipRect { id: search anchors.left: parent.left @@ -54,7 +54,7 @@ Item { } } - CustomClippingRect { + ClipRect { id: preview anchors.bottom: parent.bottom @@ -228,7 +228,7 @@ Item { anchors.fill: parent spacing: Tokens.spacing.small - CustomClippingRect { + ClipRect { id: textRect Layout.fillHeight: true diff --git a/Modules/Dashboard/Dash/User.qml b/Modules/Dashboard/Dash/User.qml index 34da84c..2e531e0 100644 --- a/Modules/Dashboard/Dash/User.qml +++ b/Modules/Dashboard/Dash/User.qml @@ -14,7 +14,7 @@ Row { padding: 20 spacing: 12 - CustomClippingRect { + ClipRect { color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2) implicitHeight: info.implicitHeight implicitWidth: info.implicitHeight diff --git a/Modules/Dashboard/Media.qml b/Modules/Dashboard/Media.qml index acf4399..311114d 100644 --- a/Modules/Dashboard/Media.qml +++ b/Modules/Dashboard/Media.qml @@ -16,7 +16,7 @@ Item { implicitWidth: 1000 implicitHeight: 320 - CustomClippingRect { + ClipRect { anchors.fill: parent radius: root.radius diff --git a/Modules/Dashboard/Processes/ProcessesList.qml b/Modules/Dashboard/Processes/ProcessesList.qml index 8f368db..d64b047 100644 --- a/Modules/Dashboard/Processes/ProcessesList.qml +++ b/Modules/Dashboard/Processes/ProcessesList.qml @@ -46,7 +46,7 @@ CustomListView { anchors.bottom: parent.bottom spacing: Tokens.spacing.extraSmall / 2 - CustomClippingRect { + ClipRect { id: iconClip Layout.fillHeight: true diff --git a/Modules/DesktopIcons/BackgroundContextMenu.qml b/Modules/DesktopIcons/BackgroundContextMenu.qml index 98050f3..92a3347 100644 --- a/Modules/DesktopIcons/BackgroundContextMenu.qml +++ b/Modules/DesktopIcons/BackgroundContextMenu.qml @@ -25,7 +25,7 @@ Item { onClicked: root.close() } - CustomClippingRect { + ClipRect { id: popupBackground readonly property real padding: 4 diff --git a/Modules/DesktopIcons/DesktopIconContextMenu.qml b/Modules/DesktopIcons/DesktopIconContextMenu.qml index 349d0cb..ea043f1 100644 --- a/Modules/DesktopIcons/DesktopIconContextMenu.qml +++ b/Modules/DesktopIcons/DesktopIconContextMenu.qml @@ -40,7 +40,7 @@ Item { visible: false z: 999 - CustomClippingRect { + ClipRect { id: popupBackground readonly property real padding: Tokens.padding.extraSmall diff --git a/Modules/Launcher/Items/WallpaperTile.qml b/Modules/Launcher/Items/WallpaperTile.qml index 293c48c..1162fee 100755 --- a/Modules/Launcher/Items/WallpaperTile.qml +++ b/Modules/Launcher/Items/WallpaperTile.qml @@ -19,7 +19,7 @@ Item { implicitHeight: tileHeight + Tokens.padding.large * 2 implicitWidth: tileWidth - CustomClippingRect { + ClipRect { id: image anchors.horizontalCenter: parent.horizontalCenter diff --git a/Modules/Lock/Center.qml b/Modules/Lock/Center.qml index 481d757..c682ef2 100644 --- a/Modules/Lock/Center.qml +++ b/Modules/Lock/Center.qml @@ -55,7 +55,7 @@ ColumnLayout { text: Time.format("dddd, d MMMM yyyy") } - CustomClippingRect { + ClipRect { Layout.alignment: Qt.AlignHCenter Layout.topMargin: Tokens.spacing.largeIncreased * 2 color: Colors.tPalette.m3surfaceContainer diff --git a/Modules/Lock/Content.qml b/Modules/Lock/Content.qml index 0323e7f..1d8e734 100644 --- a/Modules/Lock/Content.qml +++ b/Modules/Lock/Content.qml @@ -5,7 +5,7 @@ import qs.Helpers import ZShell.Config import qs.Services -CustomClippingRect { +ClipRect { id: root required property var lock diff --git a/Modules/Lock/Media.qml b/Modules/Lock/Media.qml index 326f5ba..0d08f40 100644 --- a/Modules/Lock/Media.qml +++ b/Modules/Lock/Media.qml @@ -2,12 +2,12 @@ import QtQuick import QtQuick.Layouts import Quickshell import ZShell.Components -import qs.Components import ZShell.Config +import qs.Components import qs.Helpers import qs.Services -CustomClippingRect { +ClipRect { id: root required property var lock diff --git a/Modules/Lock/NotifDock.qml b/Modules/Lock/NotifDock.qml index c441ff9..af8ed98 100644 --- a/Modules/Lock/NotifDock.qml +++ b/Modules/Lock/NotifDock.qml @@ -24,12 +24,11 @@ ColumnLayout { Layout.fillWidth: true color: Colors.palette.m3outline elide: Text.ElideRight - font.family: Config.appearance.font.family.mono - font.weight: 500 + font: Tokens.font.mono.builders.small.weight(Font.Medium).build() text: NotifServer.list.length > 0 ? qsTr("%1 notification%2").arg(NotifServer.list.length).arg(NotifServer.list.length === 1 ? "" : "s") : qsTr("Notifications") } - ClippingRectangle { + ClipRect { id: clipRect Layout.fillHeight: true diff --git a/Modules/Lock/NotifGroup.qml b/Modules/Lock/NotifGroup.qml index 0d6d6ad..12eeab1 100644 --- a/Modules/Lock/NotifGroup.qml +++ b/Modules/Lock/NotifGroup.qml @@ -85,7 +85,7 @@ CustomRect { } } - ClippingRectangle { + ClipRect { anchors.fill: parent color: root.urgency === "critical" ? Colors.palette.m3error : root.urgency === "low" ? Colors.layer(Colors.palette.m3surfaceContainerHighest, 3) : Colors.palette.m3secondaryContainer radius: Tokens.rounding.full diff --git a/Modules/Lock/UserImage.qml b/Modules/Lock/UserImage.qml index 57133db..b5d2f0b 100644 --- a/Modules/Lock/UserImage.qml +++ b/Modules/Lock/UserImage.qml @@ -1,12 +1,13 @@ import Quickshell import Quickshell.Widgets import QtQuick +import qs.Components import qs.Paths Item { id: root - ClippingRectangle { + ClipRect { anchors.fill: parent radius: Tokens.rounding.full diff --git a/Modules/Notifications/Notification.qml b/Modules/Notifications/Notification.qml index 0cf7d74..96c1bfc 100644 --- a/Modules/Notifications/Notification.qml +++ b/Modules/Notifications/Notification.qml @@ -108,7 +108,7 @@ CustomRect { visible: root.hasImage || root.hasAppIcon width: Config.notifs.sizes.image - sourceComponent: CustomClippingRect { + sourceComponent: ClipRect { color: root.modelData.urgency === NotificationUrgency.Critical ? Colors.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? Colors.layer(Colors.palette.m3surfaceContainerHighest, 2) : Colors.palette.m3secondaryContainer implicitHeight: Config.notifs.sizes.image implicitWidth: Config.notifs.sizes.image diff --git a/Modules/Resources/Cards/BatteryTank.qml b/Modules/Resources/Cards/BatteryTank.qml index 637851d..7c26d63 100644 --- a/Modules/Resources/Cards/BatteryTank.qml +++ b/Modules/Resources/Cards/BatteryTank.qml @@ -5,7 +5,7 @@ import ZShell.Config import qs.Components import qs.Services -CustomClippingRect { +ClipRect { id: root property real animPerc: UPower.displayDevice.percentage diff --git a/Modules/Resources/Cards/HeroCard.qml b/Modules/Resources/Cards/HeroCard.qml index 913dd03..d5f8a87 100644 --- a/Modules/Resources/Cards/HeroCard.qml +++ b/Modules/Resources/Cards/HeroCard.qml @@ -19,7 +19,7 @@ CustomRect { implicitWidth: 450 radius: Tokens.rounding.largeIncreased - CustomClippingRect { + ClipRect { anchors.fill: parent radius: parent.radius diff --git a/Modules/Settings/Common/PageBase.qml b/Modules/Settings/Common/PageBase.qml index 6b96653..ef43398 100644 --- a/Modules/Settings/Common/PageBase.qml +++ b/Modules/Settings/Common/PageBase.qml @@ -149,7 +149,7 @@ ColumnLayout { } } - Flickable { + CustomFlickable { id: flickable Layout.fillHeight: true diff --git a/Modules/Settings/Common/WallItem.qml b/Modules/Settings/Common/WallItem.qml index 33c80fa..84d15e5 100644 --- a/Modules/Settings/Common/WallItem.qml +++ b/Modules/Settings/Common/WallItem.qml @@ -25,7 +25,7 @@ Item { anchors.fill: parent spacing: Tokens.spacing.small - CustomClippingRect { + ClipRect { id: imgWrapper Layout.fillWidth: true diff --git a/Modules/Settings/Common/WallpaperCropper.qml b/Modules/Settings/Common/WallpaperCropper.qml index 27eaa47..966f6ee 100644 --- a/Modules/Settings/Common/WallpaperCropper.qml +++ b/Modules/Settings/Common/WallpaperCropper.qml @@ -100,16 +100,13 @@ Item { visible: opacity > 0 Behavior on opacity { - Anim { - } + Anim {} } Behavior on scale { - Anim { - } + Anim {} } Behavior on y { - Anim { - } + Anim {} } Component.onCompleted: { @@ -120,9 +117,8 @@ Item { Qt.callLater(syncCropToScreen); } - ButtonRow { - id: screenSelector - + Loader { + id: selectorLoader anchors.bottom: imageSlot.top anchors.bottomMargin: Tokens.spacing.medium anchors.left: parent.left @@ -130,25 +126,32 @@ Item { anchors.right: parent.right anchors.rightMargin: Tokens.padding.extraLarge * 2 anchors.top: parent.top - spacing: Tokens.spacing.small - Repeater { - model: wrapper.screens + active: wrapper.screens.length > 1 - delegate: TextButton { - required property int index - readonly property bool isCurrent: wrapper.selectedScreenIndex === index - required property var modelData + sourceComponent: ButtonRow { + id: screenSelector - fillWidth: true - font: Tokens.font.body.builders.large.weight(Font.DemiBold).build() - inactiveColor: isCurrent ? Colors.palette.m3primary : Qt.alpha(Colors.palette.m3surfaceContainer, 0.7) - inactiveOnColor: isCurrent ? Colors.palette.m3onPrimary : Qt.alpha(Colors.palette.m3onSurface, 0.7) - isRound: true - shapeMorph: true - text: modelData.name + spacing: Tokens.spacing.small - onClicked: wrapper.selectScreen(index) + Repeater { + model: wrapper.screens + + delegate: TextButton { + required property int index + readonly property bool isCurrent: wrapper.selectedScreenIndex === index + required property var modelData + + fillWidth: true + font: Tokens.font.body.builders.large.weight(Font.DemiBold).build() + inactiveColor: isCurrent ? Colors.palette.m3primary : Qt.alpha(Colors.palette.m3surfaceContainer, 0.7) + inactiveOnColor: isCurrent ? Colors.palette.m3onPrimary : Qt.alpha(Colors.palette.m3onSurface, 0.7) + isRound: true + shapeMorph: true + text: modelData.name + + onClicked: wrapper.selectScreen(index) + } } } } @@ -222,9 +225,9 @@ Item { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.topMargin: wrapper.buttonRowHeight + Tokens.spacing.medium + anchors.topMargin: selectorLoader.active ? wrapper.buttonRowHeight + Tokens.spacing.medium : Tokens.spacing.medium - CustomClippingRect { + ClipRect { id: fitBox readonly property real aspect: scaledImg.implicitHeight > 0 ? scaledImg.implicitWidth / scaledImg.implicitHeight : 1 @@ -357,8 +360,7 @@ Item { width: Math.round(baseWidth / zoom) Behavior on color { - CAnim { - } + CAnim {} } Component.onCompleted: { diff --git a/Modules/Settings/Content.qml b/Modules/Settings/Content.qml index 544b21e..3160a0d 100644 --- a/Modules/Settings/Content.qml +++ b/Modules/Settings/Content.qml @@ -38,6 +38,7 @@ Item { } BlobInvertedRect { + id: blobRect anchors.fill: parent borderBottom: Tokens.padding.small borderLeft: navPane.width + navPane.anchors.margins * 2 @@ -65,6 +66,7 @@ Item { anchors.bottom: parent.bottom anchors.left: navPane.right anchors.leftMargin: navPane.anchors.margins + anchors.margins + anchors.bottomMargin: blobRect.borderBottom anchors.margins: Tokens.padding.extraLarge anchors.right: parent.right anchors.top: parent.top diff --git a/Modules/Sidebar/Chat/ChatContent.qml b/Modules/Sidebar/Chat/ChatContent.qml index 7b05d0b..b136a73 100644 --- a/Modules/Sidebar/Chat/ChatContent.qml +++ b/Modules/Sidebar/Chat/ChatContent.qml @@ -436,7 +436,7 @@ Item { width: attachments.cellWidth height: width opacity: modelData ? 1 : 0 - CustomClippingRect { + ClipRect { anchors.fill: parent anchors.margins: Tokens.spacing.extraSmall diff --git a/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml b/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml index c40a051..ae9549b 100644 --- a/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml +++ b/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml @@ -337,7 +337,7 @@ Item { } } - CustomClippingRect { + ClipRect { id: expandedTool anchors.top: collapsedRow.bottom diff --git a/Modules/Sidebar/Chat/Content/CodeBlockView.qml b/Modules/Sidebar/Chat/Content/CodeBlockView.qml index 993c5e8..fcfa1d3 100644 --- a/Modules/Sidebar/Chat/Content/CodeBlockView.qml +++ b/Modules/Sidebar/Chat/Content/CodeBlockView.qml @@ -252,7 +252,7 @@ CustomRect { } } - CustomClippingRect { + CustomRect { id: codeRect anchors.left: parent.left @@ -265,6 +265,7 @@ CustomRect { implicitWidth: codeText.implicitWidth + codeFlick.anchors.margins * 2 implicitHeight: codeText.implicitHeight + codeFlick.anchors.margins * 2 color: CodeColors.active.bg + clip: true Flickable { id: codeFlick @@ -272,6 +273,9 @@ CustomRect { anchors.fill: parent anchors.margins: Tokens.padding.small + boundsBehavior: Flickable.StopAtBounds + contentWidth: codeText.implicitWidth + CustomScrollBar.horizontal: CustomScrollBar { flickable: codeFlick parent: codeFlick.parent @@ -280,16 +284,13 @@ CustomRect { anchors.right: parent.right } - TextAreaBase.flickable: TextAreaBase { + CustomText { id: codeText color: CodeColors.active.normal - layer.enabled: true - clip: false font: Tokens.font.mono.small - textFormat: root.colored ? Text.RichText : Text.PlainText + textFormat: Text.RichText text: root.colored ? root.html : root.plainForDisplay(root.code) - readOnly: true } } } diff --git a/Modules/Sidebar/Chat/Content/ProcessBlock.qml b/Modules/Sidebar/Chat/Content/ProcessBlock.qml index 43ad59a..6458e0c 100644 --- a/Modules/Sidebar/Chat/Content/ProcessBlock.qml +++ b/Modules/Sidebar/Chat/Content/ProcessBlock.qml @@ -125,7 +125,7 @@ Item { current: root.current } - CustomClippingRect { + ClipRect { id: expandedRect anchors.left: parent.left diff --git a/Modules/Sidebar/Chat/SidebarView.qml b/Modules/Sidebar/Chat/SidebarView.qml index 3c0e87f..9b43ed2 100644 --- a/Modules/Sidebar/Chat/SidebarView.qml +++ b/Modules/Sidebar/Chat/SidebarView.qml @@ -86,7 +86,7 @@ Item { } } - CustomClippingRect { + ClipRect { anchors.fill: parent anchors.leftMargin: invertedRect.borderLeft anchors.topMargin: invertedRect.borderTop diff --git a/Modules/Sidebar/NotifActionList.qml b/Modules/Sidebar/NotifActionList.qml index e70ce18..1bd33b5 100644 --- a/Modules/Sidebar/NotifActionList.qml +++ b/Modules/Sidebar/NotifActionList.qml @@ -17,76 +17,6 @@ Item { Layout.fillWidth: true implicitHeight: flickable.contentHeight - layer.enabled: true - layer.smooth: true - - layer.effect: Mask { - maskSource: gradientMask - } - - Item { - id: gradientMask - - anchors.fill: parent - layer.enabled: true - visible: false - - Rectangle { - anchors.fill: parent - - gradient: Gradient { - orientation: Gradient.Horizontal - - GradientStop { - color: Qt.rgba(0, 0, 0, 0) - position: 0 - } - - GradientStop { - color: Qt.rgba(0, 0, 0, 1) - position: 0.1 - } - - GradientStop { - color: Qt.rgba(0, 0, 0, 1) - position: 0.9 - } - - GradientStop { - color: Qt.rgba(0, 0, 0, 0) - position: 1 - } - } - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.top: parent.top - implicitWidth: parent.width / 2 - opacity: flickable.contentX > 0 ? 0 : 1 - - Behavior on opacity { - Anim { - type: Anim.DefaultEffects - } - } - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.top: parent.top - implicitWidth: parent.width / 2 - opacity: flickable.contentX < flickable.contentWidth - parent.width ? 0 : 1 - - Behavior on opacity { - Anim { - type: Anim.DefaultEffects - } - } - } - } CustomFlickable { id: flickable diff --git a/Modules/Sidebar/NotifGroup.qml b/Modules/Sidebar/NotifGroup.qml index faa67eb..4cb7b67 100644 --- a/Modules/Sidebar/NotifGroup.qml +++ b/Modules/Sidebar/NotifGroup.qml @@ -112,7 +112,7 @@ CustomRect { } } - CustomClippingRect { + ClipRect { anchors.fill: parent color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3error : root.urgency === NotificationUrgency.Low ? Colors.layer(Colors.palette.m3surfaceContainerHigh, 3) : Colors.palette.m3secondaryContainer radius: Tokens.rounding.full diff --git a/Plugins/ZShell/Internal/wallpaperservice.cpp b/Plugins/ZShell/Internal/wallpaperservice.cpp index 40fb00b..f8c9c10 100644 --- a/Plugins/ZShell/Internal/wallpaperservice.cpp +++ b/Plugins/ZShell/Internal/wallpaperservice.cpp @@ -662,6 +662,17 @@ void WallpaperService::drawSurface(WallpaperSurface* surface) { return; } + // Release the context when this scope ends (see FrameService::drawSurface). + // Holding it across the draw loop's sleep serializes the two raw-EGL clients on + // NVIDIA, which makes eglSwapBuffers fail and starves other processes' contexts. + struct ContextRelease { + EGLDisplay display; + ~ContextRelease() { + eglMakeCurrent( + display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + } contextRelease{m_eglDisplay}; + QVariantMap crops; QSize size; bool upload = false; @@ -701,7 +712,9 @@ void WallpaperService::drawSurface(WallpaperSurface* surface) { glDrawArrays(GL_TRIANGLES, 0, 3); if (!eglSwapBuffers(m_eglDisplay, target)) - qWarning() << "WallpaperService: eglSwapBuffers failed"; + qWarning() + << "WallpaperService: eglSwapBuffers failed, eglGetError = 0x" + << QString::number(unsigned(eglGetError()), 16); } void WallpaperService::addSurface(const QString& screen) { diff --git a/shell.qml b/shell.qml index fcbc98b..7458221 100644 --- a/shell.qml +++ b/shell.qml @@ -1,7 +1,5 @@ //@ pragma UseQApplication //@ pragma DefaultEnv QSG_RENDER_LOOP=threaded -// @ pragma DefaultEnv QSG_RHI_BACKEND=vulkan -//@ pragma DefaultEnv QSG_NO_VSYNC=1 //@ pragma DefaultEnv QS_NO_RELOAD_POPUP=1 //@ pragma DefaultEnv QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000 //@ pragma DropExpensiveFonts