chore: fix sidebar linter warnings

This commit is contained in:
2 * r + 2 * t 2026-03-21 16:38:48 +11:00
parent 53109b28e6
commit 8090f21499
7 changed files with 292 additions and 285 deletions

View file

@ -8,7 +8,7 @@ Item {
id: root id: root
required property Props props required property Props props
required property var visibilities required property DrawerVisibilities visibilities
ColumnLayout { ColumnLayout {
id: layout id: layout

View file

@ -13,9 +13,9 @@ StyledRect {
required property NotifData modelData required property NotifData modelData
required property Props props required property Props props
required property bool expanded required property bool expanded
required property var visibilities required property DrawerVisibilities visibilities
readonly property StyledText body: expandedContent.item?.body ?? null readonly property StyledText body: (expandedContent.item as ExpandedBody)?.body ?? null
readonly property real nonAnimHeight: expanded ? summary.implicitHeight + expandedContent.implicitHeight + expandedContent.anchors.topMargin + Appearance.padding.normal * 2 : summaryHeightMetrics.height readonly property real nonAnimHeight: expanded ? summary.implicitHeight + expandedContent.implicitHeight + expandedContent.anchors.topMargin + Appearance.padding.normal * 2 : summaryHeightMetrics.height
implicitHeight: nonAnimHeight implicitHeight: nonAnimHeight
@ -118,30 +118,7 @@ StyledRect {
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: Appearance.spacing.small / 2 anchors.topMargin: Appearance.spacing.small / 2
sourceComponent: ColumnLayout { sourceComponent: ExpandedBody {}
readonly property alias body: body
spacing: Appearance.spacing.smaller
StyledText {
id: body
Layout.fillWidth: true
textFormat: Text.MarkdownText
text: root.modelData.body.replace(/(.)\n(?!\n)/g, "$1\n\n") || qsTr("No body here! :/")
color: root.modelData.urgency === "critical" ? Colours.palette.m3secondary : Colours.palette.m3outline
wrapMode: Text.WordWrap
onLinkActivated: link => {
Quickshell.execDetached(["app2unit", "-O", "--", link]);
root.visibilities.sidebar = false;
}
}
NotifActionList {
notif: root.modelData
}
}
} }
Behavior on implicitHeight { Behavior on implicitHeight {
@ -151,6 +128,31 @@ StyledRect {
} }
} }
component ExpandedBody: ColumnLayout {
readonly property alias body: bodyText
spacing: Appearance.spacing.smaller
StyledText {
id: bodyText
Layout.fillWidth: true
textFormat: Text.MarkdownText
text: root.modelData.body.replace(/(.)\n(?!\n)/g, "$1\n\n") || qsTr("No body here! :/")
color: root.modelData.urgency === "critical" ? Colours.palette.m3secondary : Colours.palette.m3outline
wrapMode: Text.WordWrap
onLinkActivated: link => {
Quickshell.execDetached(["app2unit", "-O", "--", link]);
root.visibilities.sidebar = false;
}
}
NotifActionList {
notif: root.modelData
}
}
component WrappedLoader: Loader { component WrappedLoader: Loader {
required property bool shouldBeActive required property bool shouldBeActive

View file

@ -15,7 +15,7 @@ Item {
id: root id: root
required property Props props required property Props props
required property var visibilities required property DrawerVisibilities visibilities
readonly property int notifCount: Notifs.list.reduce((acc, n) => n.closed ? acc : acc + 1, 0) readonly property int notifCount: Notifs.list.reduce((acc, n) => n.closed ? acc : acc + 1, 0)
anchors.fill: parent anchors.fill: parent
@ -156,13 +156,14 @@ Item {
let next = null; let next = null;
for (let i = 0; i < notifList.repeater.count; i++) { for (let i = 0; i < notifList.repeater.count; i++) {
next = notifList.repeater.itemAt(i); next = notifList.repeater.itemAt(i);
if (!next?.closed) if (!next?.closed) // qmllint disable missing-property
break; break;
} }
if (next) if (next) {
next.closeAll(); next.closeAll(); // qmllint disable missing-property
else } else {
stop(); stop();
}
} }
} }

View file

@ -11,7 +11,7 @@ Item {
required property Props props required property Props props
required property Flickable container required property Flickable container
required property var visibilities required property DrawerVisibilities visibilities
readonly property alias repeater: repeater readonly property alias repeater: repeater
readonly property int spacing: Appearance.spacing.small readonly property int spacing: Appearance.spacing.small
@ -39,128 +39,130 @@ Item {
onValuesChanged: root.flagChanged() onValuesChanged: root.flagChanged()
} }
MouseArea { delegate: NotifGroupDelegate {}
id: notif }
required property int index component NotifGroupDelegate: MouseArea {
required property string modelData id: notif
readonly property bool closed: notifInner.notifCount === 0 required property int index
readonly property alias nonAnimHeight: notifInner.nonAnimHeight required property string modelData
property int startY
function closeAll(): void { readonly property bool closed: notifInner.notifCount === 0
for (const n of Notifs.notClosed.filter(n => n.appName === modelData)) readonly property alias nonAnimHeight: notifInner.nonAnimHeight
n.close(); property int startY
function closeAll(): void {
for (const n of Notifs.notClosed.filter(n => n.appName === modelData))
n.close();
}
y: {
root.flag; // Force update
let y = 0;
for (let i = 0; i < index; i++) {
const item = repeater.itemAt(i) as NotifGroupDelegate;
if (item && !item.closed)
y += item.nonAnimHeight + root.spacing;
} }
return y;
}
y: { containmentMask: QtObject {
root.flag; // Force update function contains(p: point): bool {
let y = 0; if (!root.container.contains(notif.mapToItem(root.container, p)))
for (let i = 0; i < index; i++) { return false;
const item = repeater.itemAt(i); return notifInner.contains(p);
if (!item.closed)
y += item.nonAnimHeight + root.spacing;
}
return y;
} }
}
containmentMask: QtObject { implicitWidth: root.width
function contains(p: point): bool { implicitHeight: notifInner.implicitHeight
if (!root.container.contains(notif.mapToItem(root.container, p)))
return false; hoverEnabled: true
return notifInner.contains(p); cursorShape: pressed ? Qt.ClosedHandCursor : undefined
} acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
preventStealing: true
enabled: !closed
drag.target: this
drag.axis: Drag.XAxis
onPressed: event => {
startY = event.y;
if (event.button === Qt.RightButton)
notifInner.toggleExpand(!notifInner.expanded);
else if (event.button === Qt.MiddleButton)
closeAll();
}
onPositionChanged: event => {
if (pressed) {
const diffY = event.y - startY;
if (Math.abs(diffY) > Config.notifs.expandThreshold)
notifInner.toggleExpand(diffY > 0);
} }
}
onReleased: event => {
if (Math.abs(x) < width * Config.notifs.clearThreshold)
x = 0;
else
closeAll();
}
implicitWidth: root.width ParallelAnimation {
implicitHeight: notifInner.implicitHeight running: true
hoverEnabled: true Anim {
cursorShape: pressed ? Qt.ClosedHandCursor : undefined target: notif
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton property: "opacity"
preventStealing: true from: 0
enabled: !closed to: 1
drag.target: this
drag.axis: Drag.XAxis
onPressed: event => {
startY = event.y;
if (event.button === Qt.RightButton)
notifInner.toggleExpand(!notifInner.expanded);
else if (event.button === Qt.MiddleButton)
closeAll();
} }
onPositionChanged: event => { Anim {
if (pressed) { target: notif
const diffY = event.y - startY; property: "scale"
if (Math.abs(diffY) > Config.notifs.expandThreshold) from: 0
notifInner.toggleExpand(diffY > 0); to: 1
} duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
onReleased: event => { }
if (Math.abs(x) < width * Config.notifs.clearThreshold)
x = 0; ParallelAnimation {
else running: notif.closed
closeAll();
Anim {
target: notif
property: "opacity"
to: 0
} }
Anim {
ParallelAnimation { target: notif
running: true property: "scale"
to: 0.6
Anim {
target: notif
property: "opacity"
from: 0
to: 1
}
Anim {
target: notif
property: "scale"
from: 0
to: 1
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
} }
}
ParallelAnimation { NotifGroup {
running: notif.closed id: notifInner
Anim { modelData: notif.modelData
target: notif props: root.props
property: "opacity" container: root.container
to: 0 visibilities: root.visibilities
} }
Anim {
target: notif Behavior on x {
property: "scale" Anim {
to: 0.6 duration: Appearance.anim.durations.expressiveDefaultSpatial
} easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
}
NotifGroup { Behavior on y {
id: notifInner Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
modelData: notif.modelData easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
props: root.props
container: root.container
visibilities: root.visibilities
}
Behavior on x {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
Behavior on y {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
} }
} }
} }

View file

@ -16,7 +16,7 @@ StyledRect {
required property string modelData required property string modelData
required property Props props required property Props props
required property Flickable container required property Flickable container
required property var visibilities required property DrawerVisibilities visibilities
readonly property list<var> notifs: Notifs.list.filter(n => n.appName === modelData) readonly property list<var> notifs: Notifs.list.filter(n => n.appName === modelData)
readonly property var groupProps: { readonly property var groupProps: {

View file

@ -14,13 +14,13 @@ Item {
required property list<var> notifs required property list<var> notifs
required property bool expanded required property bool expanded
required property Flickable container required property Flickable container
required property var visibilities required property DrawerVisibilities visibilities
readonly property real nonAnimHeight: { readonly property real nonAnimHeight: {
let h = -root.spacing; let h = -root.spacing;
for (let i = 0; i < repeater.count; i++) { for (let i = 0; i < repeater.count; i++) {
const item = repeater.itemAt(i); const item = repeater.itemAt(i) as NotifDelegate;
if (!item.modelData.closed && !item.previewHidden) if (item && !item.modelData.closed && !item.previewHidden)
h += item.nonAnimHeight + root.spacing; h += item.nonAnimHeight + root.spacing;
} }
return h; return h;
@ -59,149 +59,7 @@ Item {
onValuesChanged: root.flagChanged() onValuesChanged: root.flagChanged()
} }
MouseArea { delegate: NotifDelegate {}
id: notif
required property int index
required property NotifData modelData
readonly property alias nonAnimHeight: notifInner.nonAnimHeight
readonly property bool previewHidden: {
if (root.expanded)
return false;
let extraHidden = 0;
for (let i = 0; i < index; i++)
if (root.notifs[i].closed)
extraHidden++;
return index >= Config.notifs.groupPreviewNum + extraHidden;
}
property int startY
y: {
root.flag; // Force update
let y = 0;
for (let i = 0; i < index; i++) {
const item = repeater.itemAt(i);
if (!item.modelData.closed && !item.previewHidden)
y += item.nonAnimHeight + root.spacing;
}
return y;
}
containmentMask: QtObject {
function contains(p: point): bool {
if (!root.container.contains(notif.mapToItem(root.container, p)))
return false;
return notifInner.contains(p);
}
}
opacity: previewHidden ? 0 : 1
scale: previewHidden ? 0.7 : 1
implicitWidth: root.width
implicitHeight: notifInner.implicitHeight
hoverEnabled: true
cursorShape: notifInner.body?.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
preventStealing: !root.expanded
enabled: !modelData.closed
drag.target: this
drag.axis: Drag.XAxis
onPressed: event => {
startY = event.y;
if (event.button === Qt.RightButton)
root.requestToggleExpand(!root.expanded);
else if (event.button === Qt.MiddleButton)
modelData.close();
}
onPositionChanged: event => {
if (pressed && !root.expanded) {
const diffY = event.y - startY;
if (Math.abs(diffY) > Config.notifs.expandThreshold)
root.requestToggleExpand(diffY > 0);
}
}
onReleased: event => {
if (Math.abs(x) < width * Config.notifs.clearThreshold)
x = 0;
else
modelData.close();
}
Component.onCompleted: modelData.lock(this)
Component.onDestruction: modelData.unlock(this)
ParallelAnimation {
Component.onCompleted: running = !notif.previewHidden
Anim {
target: notif
property: "opacity"
from: 0
to: 1
}
Anim {
target: notif
property: "scale"
from: 0.7
to: 1
}
}
ParallelAnimation {
running: notif.modelData.closed
onFinished: notif.modelData.unlock(notif)
Anim {
target: notif
property: "opacity"
to: 0
}
Anim {
target: notif
property: "x"
to: notif.x >= 0 ? notif.width : -notif.width
}
}
Notif {
id: notifInner
anchors.fill: parent
modelData: notif.modelData
props: root.props
expanded: root.expanded
visibilities: root.visibilities
}
Behavior on opacity {
Anim {}
}
Behavior on scale {
Anim {}
}
Behavior on x {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
Behavior on y {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
}
} }
Behavior on implicitHeight { Behavior on implicitHeight {
@ -210,4 +68,148 @@ Item {
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
} }
component NotifDelegate: MouseArea {
id: notif
required property int index
required property NotifData modelData
readonly property alias nonAnimHeight: notifInner.nonAnimHeight
readonly property bool previewHidden: {
if (root.expanded)
return false;
let extraHidden = 0;
for (let i = 0; i < index; i++)
if (root.notifs[i].closed)
extraHidden++;
return index >= Config.notifs.groupPreviewNum + extraHidden;
}
property int startY
y: {
root.flag; // Force update
let y = 0;
for (let i = 0; i < index; i++) {
const item = repeater.itemAt(i) as NotifDelegate;
if (item && !item.modelData.closed && !item.previewHidden)
y += item.nonAnimHeight + root.spacing;
}
return y;
}
containmentMask: QtObject {
function contains(p: point): bool {
if (!root.container.contains(notif.mapToItem(root.container, p)))
return false;
return notifInner.contains(p);
}
}
opacity: previewHidden ? 0 : 1
scale: previewHidden ? 0.7 : 1
implicitWidth: root.width
implicitHeight: notifInner.implicitHeight
hoverEnabled: true
cursorShape: notifInner.body?.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
preventStealing: !root.expanded
enabled: !modelData.closed
drag.target: this
drag.axis: Drag.XAxis
onPressed: event => {
startY = event.y;
if (event.button === Qt.RightButton)
root.requestToggleExpand(!root.expanded);
else if (event.button === Qt.MiddleButton)
modelData.close();
}
onPositionChanged: event => {
if (pressed && !root.expanded) {
const diffY = event.y - startY;
if (Math.abs(diffY) > Config.notifs.expandThreshold)
root.requestToggleExpand(diffY > 0);
}
}
onReleased: event => {
if (Math.abs(x) < width * Config.notifs.clearThreshold)
x = 0;
else
modelData.close();
}
Component.onCompleted: modelData.lock(this)
Component.onDestruction: modelData.unlock(this)
ParallelAnimation {
Component.onCompleted: running = !notif.previewHidden
Anim {
target: notif
property: "opacity"
from: 0
to: 1
}
Anim {
target: notif
property: "scale"
from: 0.7
to: 1
}
}
ParallelAnimation {
running: notif.modelData.closed
onFinished: notif.modelData.unlock(notif)
Anim {
target: notif
property: "opacity"
to: 0
}
Anim {
target: notif
property: "x"
to: notif.x >= 0 ? notif.width : -notif.width
}
}
Notif {
id: notifInner
anchors.fill: parent
modelData: notif.modelData
props: root.props
expanded: root.expanded
visibilities: root.visibilities
}
Behavior on opacity {
Anim {}
}
Behavior on scale {
Anim {}
}
Behavior on x {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
Behavior on y {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
}
} }

View file

@ -7,7 +7,7 @@ import QtQuick
Item { Item {
id: root id: root
required property var visibilities required property DrawerVisibilities visibilities
required property var panels required property var panels
readonly property Props props: Props {} readonly property Props props: Props {}