fixed sluggish scroll glitch on launcher.qml

This commit is contained in:
SomeElse
2026-06-04 22:18:57 +00:00
parent c97bcaf1f3
commit f59b2d6aa9
21 changed files with 298 additions and 147 deletions

2
.gitignore vendored
View File

@@ -1 +1 @@
launcher/favorites.txt launcher/launcher_state.json

View File

@@ -46,7 +46,7 @@ ModuleChip {
signal dismissed(string toastId) signal dismissed(string toastId)
width: parent ? parent.width : 350 width: parent ? parent.width : 400
height: toastCard.height height: toastCard.height
property real progressVal: 1.0 property real progressVal: 1.0
@@ -65,12 +65,12 @@ ModuleChip {
NumberAnimation { NumberAnimation {
target: slideTranslate; property: "x" target: slideTranslate; property: "x"
from: toastRoot.slideX; to: 0 from: toastRoot.slideX; to: 0
duration: 320; easing.type: Easing.OutCubic duration: 380; easing.type: Easing.OutCubic
} }
NumberAnimation { NumberAnimation {
target: bubbleScale; property: "yScale" target: bubbleScale; property: "yScale"
from: 0; to: 1 from: 0; to: 1
duration: 280; easing.type: Easing.OutBack duration: 320; easing.type: Easing.OutBack
} }
} }
@@ -112,7 +112,7 @@ ModuleChip {
Rectangle { Rectangle {
id: toastCard id: toastCard
width: parent.width width: parent.width
height: toastContent.implicitHeight + (toastRoot.urgency === NotificationUrgency.Low ? 30 : 24) height: toastContent.implicitHeight + (toastRoot.urgency === NotificationUrgency.Low ? 31 : 25)
radius: 16 radius: 16
color: cardHover.hovered ? toastRoot.t.notifToastBgHover : toastRoot.t.notifToastBg color: cardHover.hovered ? toastRoot.t.notifToastBgHover : toastRoot.t.notifToastBg
@@ -121,19 +121,46 @@ ModuleChip {
: (cardHover.hovered ? toastRoot.t.notifBorderActive : toastRoot.t.notifToastBorder) : (cardHover.hovered ? toastRoot.t.notifBorderActive : toastRoot.t.notifToastBorder)
border.width: Cfg.Config.popupBorderWidth border.width: Cfg.Config.popupBorderWidth
Behavior on color { ColorAnimation { duration: 150; easing.type: Easing.OutCubic } } Behavior on color { ColorAnimation { duration: 180; easing.type: Easing.OutCubic } }
Behavior on border.color { ColorAnimation { duration: 150 } } Behavior on border.color { ColorAnimation { duration: 180 } }
// Subtle outer glow for critical notifications
Rectangle {
visible: toastRoot.urgency === NotificationUrgency.Critical
anchors.fill: parent
anchors.margins: -3
radius: parent.radius + 3
color: "transparent"
border.color: Qt.rgba(toastRoot.t.notifUrgencyCritical.r, toastRoot.t.notifUrgencyCritical.g, toastRoot.t.notifUrgencyCritical.b, 0.22)
border.width: 2
z: -1
}
HoverHandler { id: cardHover } HoverHandler { id: cardHover }
TapHandler { onTapped: toastRoot.triggerDismiss() } TapHandler { onTapped: toastRoot.triggerDismiss() }
// Left accent bar — wider with a soft glow backing
Rectangle {
id: accentGlow
width: 8
height: Math.max(18, toastCard.height - 25)
radius: 4
anchors {
left: parent.left
leftMargin: 7
verticalCenter: parent.verticalCenter
}
color: Qt.rgba(toastRoot.urgencyColor(toastRoot.urgency).r,
toastRoot.urgencyColor(toastRoot.urgency).g,
toastRoot.urgencyColor(toastRoot.urgency).b, 0.18)
}
Rectangle { Rectangle {
width: 4 width: 4
height: Math.max(16, toastCard.height - 24) height: Math.max(18, toastCard.height - 25)
radius: 2 radius: 2
anchors { anchors {
left: parent.left left: parent.left
leftMargin: 10 leftMargin: 9
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
color: toastRoot.urgencyColor(toastRoot.urgency) color: toastRoot.urgencyColor(toastRoot.urgency)
@@ -145,20 +172,20 @@ ModuleChip {
left: parent.left left: parent.left
right: parent.right right: parent.right
top: parent.top top: parent.top
leftMargin: 24 leftMargin: 25
rightMargin: 12 rightMargin: 13
topMargin: 12 topMargin: 13
} }
spacing: 4 spacing: 5
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: 6 spacing: 7
Text { Text {
text: toastRoot.urgencyIcon(toastRoot.urgency) text: toastRoot.urgencyIcon(toastRoot.urgency)
color: toastRoot.urgencyColor(toastRoot.urgency) color: toastRoot.urgencyColor(toastRoot.urgency)
font.pixelSize: 12 font.pixelSize: 11
font.bold: true font.bold: true
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
renderType: Text.NativeRendering renderType: Text.NativeRendering
@@ -166,10 +193,10 @@ ModuleChip {
Text { Text {
text: toastRoot.appName text: toastRoot.appName
color: toastRoot.t.notifToastAppName color: toastRoot.t.notifToastAppName
font.pixelSize: 12 font.pixelSize: 10
font.bold: true font.bold: true
font.capitalization: Font.AllUppercase font.capitalization: Font.AllUppercase
font.letterSpacing: 0.4 font.letterSpacing: 0.8
Layout.fillWidth: true Layout.fillWidth: true
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@@ -178,17 +205,18 @@ ModuleChip {
Text { Text {
text: toastRoot.timeStr text: toastRoot.timeStr
color: toastRoot.t.notifToastDim color: toastRoot.t.notifToastDim
font.pixelSize: 11 font.pixelSize: 10
font.bold: true
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
Rectangle { Rectangle {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
width: 20; height: 20; radius: 8 width: 18; height: 18; radius: 10
color: closeHover.hovered ? toastRoot.t.notifHistoryHover : "transparent" color: closeHover.hovered
Behavior on color { ColorAnimation { duration: 100 } } ? Qt.rgba(1, 1, 1, 0.1)
: "transparent"
Behavior on color { ColorAnimation { duration: 120 } }
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
@@ -218,16 +246,15 @@ ModuleChip {
Text { Text {
text: toastRoot.body text: toastRoot.body
color: toastRoot.t.notifToastDim color: toastRoot.t.notifToastDim
font.pixelSize: 12 font.pixelSize: 11
font.bold: true
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
maximumLineCount: 3 maximumLineCount: 3
elide: Text.ElideRight elide: Text.ElideRight
textFormat: Text.PlainText textFormat: Text.PlainText
visible: toastRoot.body !== "" visible: toastRoot.body !== ""
Layout.bottomMargin: toastRoot.urgency === NotificationUrgency.Low ? 6 : 0 Layout.bottomMargin: toastRoot.urgency === NotificationUrgency.Low ? 6 : 0
lineHeight: 1.2 lineHeight: 1.35
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
} }
@@ -236,9 +263,9 @@ ModuleChip {
visible: toastRoot.urgency === NotificationUrgency.Low && toastRoot.timeout > 0 visible: toastRoot.urgency === NotificationUrgency.Low && toastRoot.timeout > 0
anchors { anchors {
left: parent.left; right: parent.right; bottom: parent.bottom left: parent.left; right: parent.right; bottom: parent.bottom
margins: 10; bottomMargin: 10 margins: 13; bottomMargin: 10
} }
height: 4 height: 2
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
@@ -250,6 +277,7 @@ ModuleChip {
height: parent.height height: parent.height
radius: 2 radius: 2
color: toastRoot.t.notifProgressFill color: toastRoot.t.notifProgressFill
Behavior on width { NumberAnimation { duration: 80; easing.type: Easing.Linear } }
} }
} }
} }
@@ -271,7 +299,7 @@ ModuleChip {
signal dismissed(int itemIndex) signal dismissed(int itemIndex)
height: histItemContent.implicitHeight + 16 height: histItemContent.implicitHeight + 18
radius: 10 radius: 10
clip: true clip: true
color: histItemHover.hovered ? histRoot.t.notifHistoryHover : "transparent" color: histItemHover.hovered ? histRoot.t.notifHistoryHover : "transparent"
@@ -282,25 +310,35 @@ ModuleChip {
SequentialAnimation { SequentialAnimation {
id: dismissAnim id: dismissAnim
ParallelAnimation { ParallelAnimation {
NumberAnimation { target: histRoot; property: "opacity"; to: 0; duration: 150; easing.type: Easing.OutCubic } NumberAnimation { target: histRoot; property: "opacity"; to: 0; duration: 180; easing.type: Easing.OutCubic }
NumberAnimation { target: histRoot; property: "scale"; to: 0.95; duration: 150; easing.type: Easing.OutCubic } NumberAnimation { target: histRoot; property: "scale"; to: 0.94; duration: 180; easing.type: Easing.OutCubic }
} }
NumberAnimation { target: histRoot; property: "height"; to: 0; duration: 150; easing.type: Easing.InOutQuad } NumberAnimation { target: histRoot; property: "height"; to: 0; duration: 160; easing.type: Easing.InOutQuad }
ScriptAction { script: histRoot.dismissed(histRoot.itemIndex) } ScriptAction { script: histRoot.dismissed(histRoot.itemIndex) }
} }
// Glow backing behind accent bar
Rectangle {
width: 7
height: Math.max(13, histRoot.height - 16)
radius: 3
anchors { left: parent.left; leftMargin: 6; verticalCenter: parent.verticalCenter }
color: Qt.rgba(histRoot.urgencyColor(histRoot.urgency).r,
histRoot.urgencyColor(histRoot.urgency).g,
histRoot.urgencyColor(histRoot.urgency).b, 0.15)
}
Rectangle { Rectangle {
width: 3 width: 3
height: Math.max(10, histRoot.height - 16) height: Math.max(13, histRoot.height - 16)
radius: 1.5 radius: 2
anchors { left: parent.left; leftMargin: 8; verticalCenter: parent.verticalCenter } anchors { left: parent.left; leftMargin: 8; verticalCenter: parent.verticalCenter }
color: histRoot.urgencyColor(histRoot.urgency) color: histRoot.urgencyColor(histRoot.urgency)
} }
Rectangle { Rectangle {
anchors { right: parent.right; top: parent.top; margins: 6 } anchors { right: parent.right; top: parent.top; margins: 6 }
width: 18; height: 18; radius: 8 width: 18; height: 18; radius: 9
color: histCloseHover.hovered ? histRoot.t.notifHistoryHover : "transparent" color: histCloseHover.hovered ? Qt.rgba(1, 1, 1, 0.1) : "transparent"
opacity: histItemHover.hovered ? 1 : 0 opacity: histItemHover.hovered ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 150 } } Behavior on opacity { NumberAnimation { duration: 150 } }
Behavior on color { ColorAnimation { duration: 150 } } Behavior on color { ColorAnimation { duration: 150 } }
@@ -311,40 +349,39 @@ ModuleChip {
} }
Text { Text {
anchors { right: parent.right; rightMargin: 6; top: parent.top; topMargin: 8 } anchors { right: parent.right; rightMargin: 8; top: parent.top; topMargin: 8 }
text: histRoot.timeStr text: histRoot.timeStr
color: histRoot.t.notifToastDim color: histRoot.t.notifToastDim
font.pixelSize: 10 font.pixelSize: 10
font.bold: true
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering renderType: Text.NativeRendering
opacity: histItemHover.hovered ? 0 : 1 opacity: histItemHover.hovered ? 0 : 0.8
Behavior on opacity { NumberAnimation { duration: 150 } } Behavior on opacity { NumberAnimation { duration: 150 } }
} }
ColumnLayout { ColumnLayout {
id: histItemContent id: histItemContent
anchors { left: parent.left; right: parent.right; top: parent.top; leftMargin: 20; rightMargin: 40; topMargin: 8 } anchors { left: parent.left; right: parent.right; top: parent.top; leftMargin: 21; rightMargin: 39; topMargin: 8 }
spacing: 2 spacing: 2
RowLayout { RowLayout {
Layout.fillWidth: true; spacing: 5 Layout.fillWidth: true; spacing: 5
Text { text: histRoot.urgencyIcon(histRoot.urgency); color: histRoot.urgencyColor(histRoot.urgency); font.pixelSize: 10; font.bold: true; Layout.alignment: Qt.AlignVCenter; renderType: Text.NativeRendering } Text { text: histRoot.urgencyIcon(histRoot.urgency); color: histRoot.urgencyColor(histRoot.urgency); font.pixelSize: 10; font.bold: true; Layout.alignment: Qt.AlignVCenter; renderType: Text.NativeRendering }
Text { Text {
text: histRoot.appName; color: histRoot.t.notifToastAppName; font.pixelSize: 11; font.bold: true text: histRoot.appName; color: histRoot.t.notifToastAppName; font.pixelSize: 10; font.bold: true
font.capitalization: Font.AllUppercase; font.letterSpacing: 0.4; Layout.fillWidth: true; elide: Text.ElideRight; verticalAlignment: Text.AlignVCenter font.capitalization: Font.AllUppercase; font.letterSpacing: 0.6; Layout.fillWidth: true; elide: Text.ElideRight; verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
} }
Text { Text {
text: histRoot.summary; color: histRoot.t.notifToastText; font.pixelSize: 12; font.bold: true text: histRoot.summary; color: histRoot.t.notifToastText; font.pixelSize: 13; font.bold: true
Layout.fillWidth: true; elide: Text.ElideRight; textFormat: Text.PlainText; visible: histRoot.summary !== "" Layout.fillWidth: true; elide: Text.ElideRight; textFormat: Text.PlainText; visible: histRoot.summary !== ""
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
Text { Text {
text: histRoot.body; color: histRoot.t.notifToastDim; font.pixelSize: 11; font.bold: true; Layout.fillWidth: true text: histRoot.body; color: histRoot.t.notifToastDim; font.pixelSize: 10; Layout.fillWidth: true
wrapMode: Text.WordWrap; maximumLineCount: 2; elide: Text.ElideRight; textFormat: Text.PlainText; visible: histRoot.body !== ""; lineHeight: 1.2 wrapMode: Text.WordWrap; maximumLineCount: 2; elide: Text.ElideRight; textFormat: Text.PlainText; visible: histRoot.body !== ""; lineHeight: 1.3
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
} }
@@ -395,9 +432,9 @@ ModuleChip {
visible: root.unreadCount > 0 visible: root.unreadCount > 0
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
width: Math.max(14, badgeLabel.implicitWidth + 6) width: Math.max(16, badgeLabel.implicitWidth + 8)
height: 14 height: 16
radius: 7 radius: 8
color: t.notifBadgeBg color: t.notifBadgeBg
Behavior on width { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } } Behavior on width { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } }
@@ -495,7 +532,7 @@ ModuleChip {
readonly property bool atBottom: pos === "bottomleft" || pos === "bottomright" readonly property bool atBottom: pos === "bottomleft" || pos === "bottomright"
anchors { top: true; bottom: true; right: atRight; left: !atRight } anchors { top: true; bottom: true; right: atRight; left: !atRight }
implicitWidth: 350 + root.barMargin + toastPad implicitWidth: 344 + root.barMargin + toastPad
WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.namespace: "main-shell-notifications-toasts" WlrLayershell.namespace: "main-shell-notifications-toasts"
@@ -512,8 +549,8 @@ ModuleChip {
id: toastCol id: toastCol
x: toastLayer.atRight ? root.barMargin : toastLayer.toastPad x: toastLayer.atRight ? root.barMargin : toastLayer.toastPad
y: !toastLayer.atBottom ? toastLayer.edgeGap : parent.height - toastLayer.edgeGap - toastCol.height y: !toastLayer.atBottom ? toastLayer.edgeGap : parent.height - toastLayer.edgeGap - toastCol.height
spacing: 8 spacing: 10
width: 350 width: 332
Repeater { Repeater {
model: activeToasts model: activeToasts
@@ -566,7 +603,7 @@ ModuleChip {
Item { Item {
id: histClipContainer id: histClipContainer
readonly property int cardW: 340 readonly property int cardW: 352
readonly property int screenPad: root.barMargin + 10 readonly property int screenPad: root.barMargin + 10
x: { x: {
@@ -577,9 +614,9 @@ ModuleChip {
anchors.top: root.isTop ? parent.top : undefined anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom anchors.bottom: root.isTop ? undefined : parent.bottom
anchors.topMargin: root.isTop ? (root.barHeight + root.barEdgePad + 10) : 0 anchors.topMargin: root.isTop ? (root.barHeight + root.barEdgePad + 12) : 0
anchors.bottomMargin: root.isTop ? 0 : (root.barHeight + root.barEdgePad + 10) anchors.bottomMargin: root.isTop ? 0 : (root.barHeight + root.barEdgePad + 12)
height: parent.height - root.barHeight - root.barEdgePad - 10 height: parent.height - root.barHeight - root.barEdgePad - 12
clip: true clip: true
@@ -588,7 +625,7 @@ ModuleChip {
popupOpen: historyPopup.popupOpen popupOpen: historyPopup.popupOpen
isTop: root.isTop isTop: root.isTop
animEnabled: historyPopup.visible animEnabled: historyPopup.visible
height: Math.min(histHeader.implicitHeight + 56 + (notifHistory.count > 0 ? histCol.implicitHeight : 90), 520) height: Math.min(histHeader.implicitHeight + 58 + (notifHistory.count > 0 ? histCol.implicitHeight : 94), 480)
color: t.notifHistoryBg color: t.notifHistoryBg
radius: Cfg.Config.popupRadius radius: Cfg.Config.popupRadius
@@ -598,25 +635,27 @@ ModuleChip {
RowLayout { RowLayout {
id: histHeader id: histHeader
anchors { left: parent.left; right: parent.right; top: parent.top } anchors { left: parent.left; right: parent.right; top: parent.top }
anchors.topMargin: 20; anchors.leftMargin: 20; anchors.rightMargin: 20 anchors.topMargin: 16; anchors.leftMargin: 16; anchors.rightMargin: 16
spacing: 10 spacing: 10
Text { text: "󰂚"; color: t.notifToastAppName; font.pixelSize: 18; font.bold: true; Layout.alignment: Qt.AlignVCenter; renderType: Text.NativeRendering } Text { text: "󰂚"; color: t.notifToastAppName; font.pixelSize: 18; font.bold: true; Layout.alignment: Qt.AlignVCenter; renderType: Text.NativeRendering }
Text { Text {
text: "Notifications"; color: t.notifToastAppName; font.pixelSize: 15; font.bold: true text: "Notifications"; color: t.notifToastAppName; font.pixelSize: 14; font.bold: true
Layout.fillWidth: true; Layout.alignment: Qt.AlignVCenter; renderType: Text.NativeRendering Layout.fillWidth: true; Layout.alignment: Qt.AlignVCenter; renderType: Text.NativeRendering
} }
Rectangle { Rectangle {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
width: dndRow.implicitWidth + 16 width: dndRow.implicitWidth + 19
height: 24 height: 25
radius: 8 radius: 13
color: root.doNotDisturb color: root.doNotDisturb
? Qt.rgba(t.notifDnd.r, t.notifDnd.g, t.notifDnd.b, 0.18) ? Qt.rgba(t.notifDnd.r, t.notifDnd.g, t.notifDnd.b, 0.18)
: (dndHover.hovered ? t.notifHistoryHover : "transparent") : (dndHover.hovered ? t.notifHistoryHover : "transparent")
border.color: root.doNotDisturb ? t.notifDnd : "transparent" border.color: root.doNotDisturb
border.width: Cfg.Config.popupBorderWidth ? Qt.rgba(t.notifDnd.r, t.notifDnd.g, t.notifDnd.b, 0.55)
: Qt.rgba(1, 1, 1, 0.08)
border.width: 1
Behavior on color { ColorAnimation { duration: 150 } } Behavior on color { ColorAnimation { duration: 150 } }
Behavior on border.color { ColorAnimation { duration: 150 } } Behavior on border.color { ColorAnimation { duration: 150 } }
@@ -627,7 +666,7 @@ ModuleChip {
Text { Text {
text: "󰂛" text: "󰂛"
color: root.doNotDisturb ? t.notifDnd : t.notifToastDim color: root.doNotDisturb ? t.notifDnd : t.notifToastDim
font.pixelSize: 12 font.pixelSize: 11
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Behavior on color { ColorAnimation { duration: 150 } } Behavior on color { ColorAnimation { duration: 150 } }
@@ -636,7 +675,7 @@ ModuleChip {
Text { Text {
text: root.doNotDisturb ? "On" : "Off" text: root.doNotDisturb ? "On" : "Off"
color: root.doNotDisturb ? t.notifDnd : t.notifToastDim color: root.doNotDisturb ? t.notifDnd : t.notifToastDim
font.pixelSize: 11 font.pixelSize: 10
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Behavior on color { ColorAnimation { duration: 150 } } Behavior on color { ColorAnimation { duration: 150 } }
@@ -651,13 +690,15 @@ ModuleChip {
Rectangle { Rectangle {
visible: notifHistory.count > 0 visible: notifHistory.count > 0
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
width: clearText.implicitWidth + 16 width: clearText.implicitWidth + 19
height: 24 height: 25
radius: 8 radius: 13
color: clearHover.hovered ? t.notifHistoryHover : "transparent" color: clearHover.hovered ? t.notifHistoryHover : "transparent"
border.color: Qt.rgba(1, 1, 1, 0.08)
border.width: 1
Behavior on color { ColorAnimation { duration: 150 } } Behavior on color { ColorAnimation { duration: 150 } }
Text { id: clearText; anchors.centerIn: parent; text: "Clear all"; color: t.notifToastDim; font.pixelSize: 11; font.bold: true; renderType: Text.NativeRendering } Text { id: clearText; anchors.centerIn: parent; text: "Clear all"; color: t.notifToastDim; font.pixelSize: 10; font.bold: true; renderType: Text.NativeRendering }
HoverHandler { id: clearHover; cursorShape: Qt.PointingHandCursor } HoverHandler { id: clearHover; cursorShape: Qt.PointingHandCursor }
TapHandler { onTapped: clearAllAnim.start() } TapHandler { onTapped: clearAllAnim.start() }
} }
@@ -666,7 +707,7 @@ ModuleChip {
Rectangle { Rectangle {
id: histDivider id: histDivider
anchors { left: parent.left; right: parent.right; top: histHeader.bottom } anchors { left: parent.left; right: parent.right; top: histHeader.bottom }
anchors.topMargin: 12; height: 1; color: t.notifSeparator anchors.topMargin: 10; height: 1; color: t.notifSeparator; opacity: 0.6
} }
SequentialAnimation { SequentialAnimation {
@@ -674,11 +715,11 @@ ModuleChip {
ParallelAnimation { ParallelAnimation {
NumberAnimation { NumberAnimation {
target: histCol; property: "opacity" target: histCol; property: "opacity"
to: 0; duration: 220; easing.type: Easing.OutCubic to: 0; duration: 240; easing.type: Easing.OutCubic
} }
NumberAnimation { NumberAnimation {
target: clearShift; property: "y" target: clearShift; property: "y"
to: -16; duration: 220; easing.type: Easing.OutCubic to: -20; duration: 240; easing.type: Easing.OutCubic
} }
} }
ScriptAction { ScriptAction {
@@ -693,7 +734,7 @@ ModuleChip {
Flickable { Flickable {
id: histFlick id: histFlick
anchors { left: parent.left; right: parent.right; top: histDivider.bottom; bottom: parent.bottom } anchors { left: parent.left; right: parent.right; top: histDivider.bottom; bottom: parent.bottom }
anchors.leftMargin: 2; anchors.rightMargin: 8 anchors.leftMargin: 4; anchors.rightMargin: 6
anchors.topMargin: 6; anchors.bottomMargin: 8; clip: true anchors.topMargin: 6; anchors.bottomMargin: 8; clip: true
contentHeight: histCol.implicitHeight contentHeight: histCol.implicitHeight
flickableDirection: Flickable.VerticalFlick flickableDirection: Flickable.VerticalFlick
@@ -703,14 +744,14 @@ ModuleChip {
id: histCol id: histCol
opacity: 1 opacity: 1
transform: Translate { id: clearShift; y: 0 } transform: Translate { id: clearShift; y: 0 }
width: histFlick.width; spacing: 2; topPadding: 4; bottomPadding: 4; leftPadding: 2; rightPadding: 8 width: histFlick.width; spacing: 2; topPadding: 2; bottomPadding: 2; leftPadding: 4; rightPadding: 6
Item { Item {
width: histCol.width - 16; height: 90; visible: notifHistory.count === 0 width: histCol.width - 16; height: 94; visible: notifHistory.count === 0
ColumnLayout { ColumnLayout {
anchors.centerIn: parent; spacing: 8 anchors.centerIn: parent; spacing: 8
Text { text: "󰂚"; color: t.notifHistoryEmpty; font.pixelSize: 30; font.bold: true; Layout.alignment: Qt.AlignHCenter; renderType: Text.NativeRendering } Text { text: "󰂚"; color: t.notifHistoryEmpty; font.pixelSize: 29; font.bold: true; Layout.alignment: Qt.AlignHCenter; renderType: Text.NativeRendering; opacity: 0.5 }
Text { text: "No notifications"; color: t.notifHistoryEmpty; font.pixelSize: 12; font.bold: true; Layout.alignment: Qt.AlignHCenter; renderType: Text.NativeRendering } Text { text: "No notifications"; color: t.notifHistoryEmpty; font.pixelSize: 13; font.bold: true; Layout.alignment: Qt.AlignHCenter; renderType: Text.NativeRendering; opacity: 0.5 }
} }
} }

View File

@@ -207,6 +207,8 @@ QtObject {
readonly property color launcherPill: "#4481c7c7" readonly property color launcherPill: "#4481c7c7"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22cbdc3d" readonly property color launcherHover: "#22cbdc3d"
readonly property color launcherSelected: "#44cbdc3d" readonly property color launcherSelected: "#44cbdc3d"

View File

@@ -207,6 +207,8 @@ QtObject {
readonly property color launcherPill: "#441e3a5f" readonly property color launcherPill: "#441e3a5f"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#2200d9ff" readonly property color launcherHover: "#2200d9ff"
readonly property color launcherSelected: "#4400d9ff" readonly property color launcherSelected: "#4400d9ff"

View File

@@ -215,6 +215,8 @@ QtObject {
readonly property color launcherPill: "#444a5d6e" readonly property color launcherPill: "#444a5d6e"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#33f2b425" readonly property color launcherHover: "#33f2b425"
readonly property color launcherSelected: "#44c19375" readonly property color launcherSelected: "#44c19375"

View File

@@ -207,6 +207,8 @@ QtObject {
readonly property color launcherPill: "#444a5d6e" readonly property color launcherPill: "#444a5d6e"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22ebc6a0" readonly property color launcherHover: "#22ebc6a0"
readonly property color launcherSelected: "#44ebc6a0" readonly property color launcherSelected: "#44ebc6a0"

View File

@@ -215,6 +215,8 @@ QtObject {
readonly property color launcherPill: "#44614d4a" readonly property color launcherPill: "#44614d4a"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22e0533c" readonly property color launcherHover: "#22e0533c"
readonly property color launcherSelected: "#44e0533c" readonly property color launcherSelected: "#44e0533c"

View File

@@ -207,6 +207,8 @@ QtObject {
readonly property color launcherPill: "#444a566e" readonly property color launcherPill: "#444a566e"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22f0a1ba" readonly property color launcherHover: "#22f0a1ba"
readonly property color launcherSelected: "#44f0a1ba" readonly property color launcherSelected: "#44f0a1ba"

View File

@@ -207,6 +207,8 @@ QtObject {
readonly property color launcherPill: "#443d4a6d" readonly property color launcherPill: "#443d4a6d"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22bdf0ff" readonly property color launcherHover: "#22bdf0ff"
readonly property color launcherSelected: "#44bdf0ff" readonly property color launcherSelected: "#44bdf0ff"

View File

@@ -218,6 +218,8 @@ QtObject {
readonly property color launcherPill: "#44284038" readonly property color launcherPill: "#44284038"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#224a8c5c" readonly property color launcherHover: "#224a8c5c"
readonly property color launcherSelected: "#444a8c5c" readonly property color launcherSelected: "#444a8c5c"

View File

@@ -216,6 +216,8 @@ QtObject {
readonly property color launcherPill: "#444a5d6e" readonly property color launcherPill: "#444a5d6e"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22c19375" readonly property color launcherHover: "#22c19375"
readonly property color launcherSelected: "#44c19375" readonly property color launcherSelected: "#44c19375"

View File

@@ -215,6 +215,8 @@ QtObject {
readonly property color launcherPill: "#442e7d32" readonly property color launcherPill: "#442e7d32"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22ff5722" readonly property color launcherHover: "#22ff5722"
readonly property color launcherSelected: "#44ff5722" readonly property color launcherSelected: "#44ff5722"

View File

@@ -218,6 +218,8 @@ QtObject {
readonly property color launcherPill: "#44203060" readonly property color launcherPill: "#44203060"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22b068d8" readonly property color launcherHover: "#22b068d8"
readonly property color launcherSelected: "#44b068d8" readonly property color launcherSelected: "#44b068d8"

View File

@@ -208,6 +208,8 @@ QtObject {
readonly property color launcherPill: "#44565f89" readonly property color launcherPill: "#44565f89"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22ffb86c" readonly property color launcherHover: "#22ffb86c"
readonly property color launcherSelected: "#44ffb86c" readonly property color launcherSelected: "#44ffb86c"

View File

@@ -207,6 +207,8 @@ QtObject {
readonly property color launcherPill: "#4431748f" readonly property color launcherPill: "#4431748f"
readonly property color launcherText: "#ffe0def4" readonly property color launcherText: "#ffe0def4"
readonly property color launcherDim: "#ff6e6a86" readonly property color launcherDim: "#ff6e6a86"
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: "#ff9ccfd8" readonly property color launcherAccent: "#ff9ccfd8"
readonly property color launcherHover: "#4431748f" readonly property color launcherHover: "#4431748f"
readonly property color launcherSelected: "#6631748f" readonly property color launcherSelected: "#6631748f"

View File

@@ -218,6 +218,8 @@ QtObject {
readonly property color launcherPill: "#444a4068" readonly property color launcherPill: "#444a4068"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#224ec0b8" readonly property color launcherHover: "#224ec0b8"
readonly property color launcherSelected: "#444ec0b8" readonly property color launcherSelected: "#444ec0b8"

View File

@@ -215,6 +215,8 @@ QtObject {
readonly property color launcherPill: "#444a5270" readonly property color launcherPill: "#444a5270"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22c4889e" readonly property color launcherHover: "#22c4889e"
readonly property color launcherSelected: "#44c4889e" readonly property color launcherSelected: "#44c4889e"

View File

@@ -207,6 +207,8 @@ QtObject {
readonly property color launcherPill: "#44ffb7ce" readonly property color launcherPill: "#44ffb7ce"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22ff7eb9" readonly property color launcherHover: "#22ff7eb9"
readonly property color launcherSelected: "#44ff7eb9" readonly property color launcherSelected: "#44ff7eb9"

View File

@@ -219,6 +219,8 @@ QtObject {
readonly property color launcherPill: "#444a3d6e" readonly property color launcherPill: "#444a3d6e"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: textDim readonly property color launcherDim: textDim
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#22b09de8" readonly property color launcherHover: "#22b09de8"
readonly property color launcherSelected: "#44b09de8" readonly property color launcherSelected: "#44b09de8"

View File

@@ -216,6 +216,8 @@ QtObject {
readonly property color launcherPill: "#444a5d6e" readonly property color launcherPill: "#444a5d6e"
readonly property color launcherText: textMain readonly property color launcherText: textMain
readonly property color launcherDim: "#ff92979b" readonly property color launcherDim: "#ff92979b"
readonly property color launcherStar: launcherDim
readonly property color launcherStarHover: accent
readonly property color launcherAccent: accent readonly property color launcherAccent: accent
readonly property color launcherHover: "#2289b4fa" readonly property color launcherHover: "#2289b4fa"
readonly property color launcherSelected: "#4489b4fa" readonly property color launcherSelected: "#4489b4fa"

View File

@@ -34,7 +34,8 @@ PanelWindow {
property bool loading: false property bool loading: false
property int lastCacheUpdate: 0 property int lastCacheUpdate: 0
property var favoriteIds: [] property var favoriteIds: []
readonly property string favoritesPath: Quickshell.env("HOME") + "/.config/quickshell/launcher/favorites.txt" property var accessCounts: ({})
readonly property string statePath: Quickshell.env("HOME") + "/.config/quickshell/launcher/launcher_state.json"
readonly property int defaultIndex: Cfg.Config.launcherSelectFirst ? 0 : -1 readonly property int defaultIndex: Cfg.Config.launcherSelectFirst ? 0 : -1
@@ -48,15 +49,31 @@ PanelWindow {
filtered = allItems.filter(i => i.name.toLowerCase().startsWith(q)) filtered = allItems.filter(i => i.name.toLowerCase().startsWith(q))
} }
const favs = filtered.filter(i => root.favoriteIds.includes(i.id)) const favs = filtered.filter(i => root.favoriteIds.includes(i.id))
const rest = filtered.filter(i => !root.favoriteIds.includes(i.id)) let rest = filtered.filter(i => !root.favoriteIds.includes(i.id))
rest.sort((a, b) => (root.accessCounts[b.id] || 0) - (root.accessCounts[a.id] || 0))
const result = [] const result = []
if (favs.length > 0) if (favs.length > 0) {
result.push(...favs.map(i => Object.assign({}, i, { section: "Favorites" }))) result.push({ isHeader: true, section: "Favorites" })
if (rest.length > 0) for (let i = 0; i < favs.length; i++)
result.push(...rest.map(i => Object.assign({}, i, { section: "All Applications" }))) result.push(Object.assign({}, favs[i], { isHeader: false }))
}
if (rest.length > 0) {
result.push({ isHeader: true, section: "All Applications" })
for (let i = 0; i < rest.length; i++)
result.push(Object.assign({}, rest[i], { isHeader: false }))
}
return result return result
} }
function skipHeader(idx, dir) {
while (idx >= 0 && idx < root.filteredItems.length) {
const item = root.filteredItems[idx]
if (item && !item.isHeader) return idx
idx += dir
}
return -1
}
function toggle() { function toggle() {
if (!_isOpen) { if (!_isOpen) {
var fm = Hyprland.focusedMonitor var fm = Hyprland.focusedMonitor
@@ -73,8 +90,9 @@ PanelWindow {
_isOpen = true _isOpen = true
searchInput.text = "" searchInput.text = ""
resultsList.currentIndex = root.defaultIndex resultsList.currentIndex = root.defaultIndex
Qt.callLater(() => resultsList.positionViewAtBeginning())
loadItems() loadItems()
loadFavorites() loadState()
Qt.callLater(() => searchInput.forceActiveFocus()) Qt.callLater(() => searchInput.forceActiveFocus())
} }
@@ -147,20 +165,16 @@ PanelWindow {
return args return args
} }
function loadFavorites() { function loadState() {
favoritesReadProc.command = ["sh", "-c", "cat " + shellQuote(favoritesPath) + " 2>/dev/null || true"] stateReadProc.command = ["sh", "-c", "cat " + shellQuote(statePath) + " 2>/dev/null || true"]
favoritesReadProc.running = true stateReadProc.running = true
} }
function saveFavorites() { function saveState() {
if (favoriteIds.length === 0) { const data = JSON.stringify({ favorites: favoriteIds, access: accessCounts })
favoritesWriteProc.command = ["sh", "-c", ": > " + shellQuote(favoritesPath)] stateWriteProc.command = ["sh", "-c",
} else { "printf '%s' " + shellQuote(data) + " > " + shellQuote(statePath)]
const quoted = favoriteIds.map(id => shellQuote(id)).join(" ") stateWriteProc.running = true
favoritesWriteProc.command = ["sh", "-c",
"printf '%s\\n' " + quoted + " > " + shellQuote(favoritesPath)]
}
favoritesWriteProc.running = true
} }
function toggleFavorite(itemId) { function toggleFavorite(itemId) {
@@ -172,7 +186,14 @@ PanelWindow {
arr.push(itemId) arr.push(itemId)
} }
favoriteIds = arr favoriteIds = arr
saveFavorites() saveState()
}
function incrementAccess(itemId) {
const counts = Object.assign({}, accessCounts)
counts[itemId] = (counts[itemId] || 0) + 1
accessCounts = counts
saveState()
} }
function launch(item) { function launch(item) {
@@ -188,6 +209,7 @@ PanelWindow {
launchProc.running = true launchProc.running = true
console.log("Launching: " + cleanExec) console.log("Launching: " + cleanExec)
incrementAccess(item.id)
close() close()
} }
@@ -238,20 +260,28 @@ PanelWindow {
Process { id: launchProc } Process { id: launchProc }
Process { Process {
id: favoritesReadProc id: stateReadProc
property string rawData: "" property string rawData: ""
stdout: SplitParser { onRead: data => favoritesReadProc.rawData += data + "\n" } stdout: SplitParser { onRead: data => stateReadProc.rawData += data + "\n" }
onRunningChanged: { onRunningChanged: {
if (!running) { if (!running) {
if (rawData.trim()) { if (rawData.trim()) {
root.favoriteIds = rawData.trim().split("\n").filter(l => l.length > 0) try {
const state = JSON.parse(rawData.trim())
if (Array.isArray(state.favorites))
root.favoriteIds = state.favorites
if (state.access && typeof state.access === "object")
root.accessCounts = state.access
} catch (e) {
console.log("Failed to parse launcher state: " + e)
}
} }
rawData = "" rawData = ""
} }
} }
} }
Process { id: favoritesWriteProc } Process { id: stateWriteProc }
MouseArea { MouseArea {
@@ -282,7 +312,7 @@ PanelWindow {
height: targetHeight height: targetHeight
Behavior on height { Behavior on height {
enabled: root._isOpen enabled: root._isOpen
NumberAnimation { duration: 154; easing.type: Easing.OutCubic } NumberAnimation { duration: 80; easing.type: Easing.OutCubic }
} }
radius: Cfg.Config.popupRadius radius: Cfg.Config.popupRadius
@@ -328,29 +358,33 @@ PanelWindow {
onTextChanged: resultsList.currentIndex = root.defaultIndex onTextChanged: resultsList.currentIndex = root.defaultIndex
Keys.onReturnPressed: { Keys.onReturnPressed: {
if (root.filteredItems.length > 0) { const idx = root.skipHeader(Math.max(0, resultsList.currentIndex), 1)
root.launch(root.filteredItems[Math.max(0, resultsList.currentIndex)]) if (idx >= 0)
} root.launch(root.filteredItems[idx])
} }
Keys.onDownPressed: { Keys.onDownPressed: {
root._keyboardNav = true root._keyboardNav = true
if (resultsList.currentIndex < 0) { var next = resultsList.currentIndex < 0 ? 0 : resultsList.currentIndex + 1
resultsList.currentIndex = 0; if (next >= resultsList.count) next = resultsList.count - 1
} else { next = root.skipHeader(next, 1)
resultsList.currentIndex = Math.min(resultsList.currentIndex + 1, resultsList.count - 1) if (next < 0) next = root.skipHeader(0, 1)
if (next >= 0) {
resultsList.currentIndex = next
resultsList.positionViewAtIndex(next, ListView.Contain)
} }
resultsList.positionViewAtIndex(resultsList.currentIndex, ListView.Contain)
} }
Keys.onUpPressed: { Keys.onUpPressed: {
root._keyboardNav = true root._keyboardNav = true
if (resultsList.currentIndex < 0) { var next = resultsList.currentIndex < 0 ? resultsList.count - 1 : resultsList.currentIndex - 1
resultsList.currentIndex = resultsList.count - 1; if (next < 0) next = 0
} else { next = root.skipHeader(next, -1)
resultsList.currentIndex = Math.max(resultsList.currentIndex - 1, 0) if (next < 0) next = root.skipHeader(resultsList.count - 1, -1)
if (next >= 0) {
resultsList.currentIndex = next
resultsList.positionViewAtIndex(next, ListView.Contain)
} }
resultsList.positionViewAtIndex(resultsList.currentIndex, ListView.Contain)
} }
} }
} }
@@ -361,49 +395,77 @@ PanelWindow {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: listHeight Layout.preferredHeight: listHeight
property int listHeight: Math.min(contentHeight, 400) // Avoid reacting to contentHeight changes from lazy delegate
Behavior on listHeight { // instantiation during scroll — only animate on model count changes.
NumberAnimation { duration: 154; easing.type: Easing.OutCubic } property int listHeight: 0
NumberAnimation {
id: listHeightAnim
target: resultsList
property: "listHeight"
duration: 80
easing.type: Easing.OutCubic
} }
function _syncListHeight() {
var h = Math.min(contentHeight, 400)
if (h === listHeight) return
listHeightAnim.stop()
listHeightAnim.from = listHeight
listHeightAnim.to = h
listHeightAnim.start()
}
onCountChanged: Qt.callLater(_syncListHeight)
Component.onCompleted: Qt.callLater(_syncListHeight)
clip: true clip: true
model: root.filteredItems model: root.filteredItems
currentIndex: root.defaultIndex currentIndex: root.defaultIndex
spacing: 2 spacing: 2
snapMode: ListView.NoSnap
highlightRangeMode: ListView.NoHighlightRange
cacheBuffer: 400
reuseItems: true
pixelAligned: false
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
section.property: "section" onModelChanged: {
section.criteria: ViewSection.FullString currentIndex = root.defaultIndex
section.delegate: Rectangle { for (let i = 0; i < count; i++) {
width: resultsList.width const md = root.filteredItems[i]
height: 28 if (md && !md.isHeader) {
color: "transparent" currentIndex = i
Text { break
anchors { left: parent.left; leftMargin: 12; verticalCenter: parent.verticalCenter } }
text: section
color: t.launcherDim
font.pixelSize: 11
font.weight: Font.Bold
} }
Qt.callLater(() => positionViewAtBeginning())
} }
onModelChanged: currentIndex = root.defaultIndex
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 100; easing.type: Easing.InQuad }
}
delegate: Rectangle { delegate: Rectangle {
width: resultsList.width width: resultsList.width
height: 38 height: 38
radius: 8 radius: modelData.isHeader ? 0 : 8
property bool hovered: false color: modelData.isHeader ? "transparent"
: (starHovered || hovered) ? t.launcherHover
color: hovered ? t.launcherHover
: (resultsList.currentIndex === index && index !== -1 : (resultsList.currentIndex === index && index !== -1
? t.launcherSelected : "transparent") ? t.launcherSelected : "transparent")
property bool hovered: false
property bool starHovered: false
Text {
visible: modelData.isHeader
anchors { left: parent.left; leftMargin: 12; verticalCenter: parent.verticalCenter }
text: modelData.section || ""
color: t.launcherDim
font.pixelSize: 13
font.weight: Font.Bold
}
RowLayout { RowLayout {
visible: !modelData.isHeader
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.rightMargin: 12 anchors.rightMargin: 12
@@ -417,10 +479,10 @@ PanelWindow {
id: appIcon id: appIcon
anchors.fill: parent anchors.fill: parent
source: modelData.icon ? "image://icon/" + modelData.icon : "" source: modelData.icon ? "image://icon/" + modelData.icon : ""
sourceSize: Qt.size(64, 64) sourceSize: Qt.size(64, 64)
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
smooth: true smooth: true
mipmap: Cfg.Config.launcherMipmapIcons mipmap: Cfg.Config.launcherMipmapIcons
visible: status === Image.Ready visible: status === Image.Ready
} }
@@ -442,14 +504,22 @@ PanelWindow {
} }
Item { Item {
width: 22; height: 22 width: 26; height: 26
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Text { Text {
id: starText
anchors.centerIn: parent anchors.centerIn: parent
text: root.favoriteIds.includes(modelData.id) ? "★" : "☆" text: root.favoriteIds.includes(modelData.id) ? "★" : "☆"
color: root.favoriteIds.includes(modelData.id) ? t.launcherAccent : t.launcherDim font.pixelSize: 18
font.pixelSize: 14
readonly property bool isFav: root.favoriteIds.includes(modelData.id)
color: starHovered ? t.launcherStarHover
: (isFav ? t.launcherAccent : t.launcherStar)
Behavior on color {
ColorAnimation { duration: 180; easing.type: Easing.OutCubic }
}
} }
} }
} }
@@ -458,8 +528,12 @@ PanelWindow {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onEntered: parent.hovered = true onEntered: parent.hovered = true
onExited: parent.hovered = false onExited: { parent.hovered = false; parent.starHovered = false }
onPositionChanged: mouse => {
parent.starHovered = !modelData.isHeader && (mouse.x >= width - 46)
}
onClicked: mouse => { onClicked: mouse => {
if (modelData.isHeader) return
if (mouse.x >= width - 46) { if (mouse.x >= width - 46) {
root.toggleFavorite(modelData.id) root.toggleFavorite(modelData.id)
} else { } else {