Files

171 lines
5.4 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import Quickshell.Services.Notifications
import qs.Common
import qs.Services
import "../../Common/htmlElide.js" as HtmlElide
QtObject {
id: root
required property IslandController controller
required property var targetScreen
property bool enabled: true
property var currentWrapper: null
property string appName: ""
property string summary: ""
property string body: ""
property string timeText: ""
property string imageSource: ""
property string fallbackIcon: "material:notifications"
property string fallbackText: ""
property string actionLabel: ""
property bool critical: false
property bool important: false
readonly property bool hasAction: actionLabel.length > 0
readonly property bool wrapperTimeoutHeld: (controller.notificationActive && controller.timeoutSuspended) || controller.notificationHeldForSystem
function scheduleDisplayFieldClear() {
displayFieldClearTimer.restart();
}
function clearDisplayFields() {
if (currentWrapper)
return;
appName = "";
summary = "";
body = "";
timeText = "";
imageSource = "";
fallbackIcon = "material:notifications";
fallbackText = "";
actionLabel = "";
critical = false;
important = false;
}
function wrapperTimeout(wrapper) {
const interval = wrapper?.timer?.interval ?? -1;
return interval >= 0 ? interval : 5000;
}
function applyWrapperTimeoutHold() {
const timer = currentWrapper?.timer;
if (!timer)
return;
if (wrapperTimeoutHeld) {
timer.stop();
return;
}
if (currentWrapper.popup && timer.interval > 0)
timer.restart();
}
function releaseWrapperTimeoutHold() {
const timer = currentWrapper?.timer;
if (!timer || !currentWrapper.popup || timer.interval <= 0)
return;
timer.restart();
}
function adopt(wrapper) {
if (!enabled || !wrapper || !NotificationService.isFocusedScreen(root.targetScreen))
return false;
const isCritical = wrapper.urgency === NotificationUrgency.Critical;
if (!controller.canRequestNotification(isCritical))
return false;
releaseWrapperTimeoutHold();
displayFieldClearTimer.stop();
currentWrapper = wrapper;
appName = wrapper.appName || I18n.tr("Notification", "island notification face: fallback app name");
summary = HtmlElide.plainText(wrapper.summary) || appName;
body = HtmlElide.plainText(wrapper.body);
timeText = wrapper.timeStr || "";
imageSource = wrapper.displayImage;
fallbackIcon = wrapper.fallbackIconName || "material:notifications";
fallbackText = appName.charAt(0).toUpperCase();
critical = isCritical;
important = !isCritical && wrapper.urgency === NotificationUrgency.Normal && fallbackIcon.startsWith("material:battery");
const actions = wrapper.actions || [];
actionLabel = actions.length > 0 ? (actions[0].text || I18n.tr("Open", "island notification face: default action button")) : "";
controller.notificationTimeout = wrapperTimeout(wrapper);
const accepted = controller.requestNotification(isCritical);
applyWrapperTimeoutHold();
return accepted;
}
function refreshDeduplicated(wrapper) {
if (!wrapper || wrapper !== currentWrapper)
return;
controller.refreshNotification();
applyWrapperTimeoutHold();
}
onWrapperTimeoutHeldChanged: applyWrapperTimeoutHold()
function syncVisibleNotifications() {
const visible = NotificationService.visibleNotifications || [];
const latest = visible.length > 0 ? visible[visible.length - 1] : null;
if (latest && (latest === currentWrapper || adopt(latest)))
return;
if (!currentWrapper || visible.indexOf(currentWrapper) !== -1)
return;
currentWrapper = null;
controller.completeNotification();
scheduleDisplayFieldClear();
}
onEnabledChanged: {
if (enabled) {
syncVisibleNotifications();
return;
}
if (!currentWrapper)
return;
currentWrapper = null;
controller.completeNotification();
scheduleDisplayFieldClear();
}
function activate() {
const actions = currentWrapper?.actions || [];
if (actions.length > 0)
actions[0].invoke();
dismiss();
}
function dismiss() {
const wrapper = currentWrapper;
currentWrapper = null;
controller.completeNotification();
scheduleDisplayFieldClear();
if (wrapper)
NotificationService.dismissNotification(wrapper);
}
property Connections notificationConnections: Connections {
target: NotificationService
enabled: root.enabled
function onVisibleNotificationsChanged() {
root.syncVisibleNotifications();
}
function onNotificationDeduplicated(wrapper) {
root.refreshDeduplicated(wrapper);
}
}
property Timer displayFieldClearTimer: Timer {
interval: 400
onTriggered: root.clearDisplayFields()
}
Component.onCompleted: syncVisibleNotifications()
}