mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-19 17:45:21 -04:00
feat(notifications): add opt-in timeout progress bar on popups (#2587)
Adds a thin bar pinned to the bottom of the notification card that drains full->empty over the auto-dismiss timer, as a visual countdown to dismissal. Opt-in via notificationShowTimeoutBar (default off), with a toggle in Settings > Notifications. Shown for any timed notification (timer.interval > 0, including timed criticals); inset by the corner radius, and frozen while hovered or during the exit animation. Plain Rectangle - no offscreen textures or shader passes. A Connections on the timer resets the bar on every (re)start, including the in-place restart on a deduped notification. Co-authored-by: bogdan-velicu <hydrotech074@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -695,6 +695,7 @@ Singleton {
|
|||||||
property int notificationTimeoutNormal: 5000
|
property int notificationTimeoutNormal: 5000
|
||||||
property int notificationTimeoutCritical: 0
|
property int notificationTimeoutCritical: 0
|
||||||
property bool notificationCompactMode: false
|
property bool notificationCompactMode: false
|
||||||
|
property bool notificationShowTimeoutBar: false
|
||||||
property bool notificationDedupeEnabled: true
|
property bool notificationDedupeEnabled: true
|
||||||
property int notificationPopupPosition: SettingsData.Position.Top
|
property int notificationPopupPosition: SettingsData.Position.Top
|
||||||
property int notificationAnimationSpeed: SettingsData.AnimationSpeed.Short
|
property int notificationAnimationSpeed: SettingsData.AnimationSpeed.Short
|
||||||
|
|||||||
@@ -406,6 +406,7 @@ var SPEC = {
|
|||||||
notificationTimeoutNormal: { def: 5000 },
|
notificationTimeoutNormal: { def: 5000 },
|
||||||
notificationTimeoutCritical: { def: 0 },
|
notificationTimeoutCritical: { def: 0 },
|
||||||
notificationCompactMode: { def: false },
|
notificationCompactMode: { def: false },
|
||||||
|
notificationShowTimeoutBar: { def: false },
|
||||||
notificationDedupeEnabled: { def: true },
|
notificationDedupeEnabled: { def: true },
|
||||||
notificationPopupPosition: { def: 0 },
|
notificationPopupPosition: { def: 0 },
|
||||||
notificationAnimationSpeed: { def: 1 },
|
notificationAnimationSpeed: { def: 1 },
|
||||||
|
|||||||
@@ -727,6 +727,51 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timeout progress bar: drains as the dismiss timer runs; inset by
|
||||||
|
// the corner radius and frozen while hovered or during exit.
|
||||||
|
Rectangle {
|
||||||
|
id: timeoutBar
|
||||||
|
|
||||||
|
readonly property bool active: SettingsData.notificationShowTimeoutBar && notificationData && notificationData.timer && notificationData.timer.interval > 0
|
||||||
|
property real progress: 1
|
||||||
|
readonly property real surfaceRadius: win.connectedFrameMode ? Theme.connectedSurfaceRadius : Theme.cornerRadius
|
||||||
|
|
||||||
|
visible: active && progress > 0
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: surfaceRadius
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
width: Math.max(0, parent.width - surfaceRadius * 2) * progress
|
||||||
|
height: Math.max(2, Theme.snap(3, win.dpr))
|
||||||
|
radius: height / 2
|
||||||
|
z: 50
|
||||||
|
opacity: 0.9
|
||||||
|
color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Theme.error : Theme.primary
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: progressAnim
|
||||||
|
target: timeoutBar
|
||||||
|
property: "progress"
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
duration: (notificationData && notificationData.timer && notificationData.timer.interval > 0) ? notificationData.timer.interval : 5000
|
||||||
|
running: timeoutBar.active && notificationData && notificationData.timer && notificationData.timer.running && !win.exiting
|
||||||
|
easing.type: Easing.Linear
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset to full on every (re)start, including an in-place
|
||||||
|
// restart on a deduped notification (running stays true, so the
|
||||||
|
// bound animation alone wouldn't re-fire).
|
||||||
|
Connections {
|
||||||
|
target: timeoutBar.active ? notificationData.timer : null
|
||||||
|
function onRunningChanged() {
|
||||||
|
if (notificationData && notificationData.timer && notificationData.timer.running && !win.exiting) {
|
||||||
|
timeoutBar.progress = 1;
|
||||||
|
progressAnim.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LayoutMirroring.enabled: I18n.isRtl
|
LayoutMirroring.enabled: I18n.isRtl
|
||||||
LayoutMirroring.childrenInherit: true
|
LayoutMirroring.childrenInherit: true
|
||||||
|
|
||||||
|
|||||||
@@ -273,6 +273,15 @@ Item {
|
|||||||
onToggled: checked => SettingsData.set("notificationCompactMode", checked)
|
onToggled: checked => SettingsData.set("notificationCompactMode", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
settingKey: "notificationShowTimeoutBar"
|
||||||
|
tags: ["notification", "timeout", "progress", "bar", "timer", "countdown"]
|
||||||
|
text: I18n.tr("Timeout Progress Bar")
|
||||||
|
description: I18n.tr("Show a bar that drains as the popup's auto-dismiss timer runs")
|
||||||
|
checked: SettingsData.notificationShowTimeoutBar
|
||||||
|
onToggled: checked => SettingsData.set("notificationShowTimeoutBar", checked)
|
||||||
|
}
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "notificationDedupeEnabled"
|
settingKey: "notificationDedupeEnabled"
|
||||||
tags: ["notification", "duplicate", "dedupe", "stack", "coalesce", "repeat"]
|
tags: ["notification", "duplicate", "dedupe", "stack", "coalesce", "repeat"]
|
||||||
|
|||||||
Reference in New Issue
Block a user