mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-13 00:42:49 -05:00
fix notification dismiss performance
This commit is contained in:
@@ -95,6 +95,8 @@ Singleton {
|
|||||||
property color error: currentThemeData.error || "#F2B8B5"
|
property color error: currentThemeData.error || "#F2B8B5"
|
||||||
property color warning: currentThemeData.warning || "#FF9800"
|
property color warning: currentThemeData.warning || "#FF9800"
|
||||||
property color info: currentThemeData.info || "#2196F3"
|
property color info: currentThemeData.info || "#2196F3"
|
||||||
|
property color tempWarning: "#ff9933"
|
||||||
|
property color tempDanger: "#ff5555"
|
||||||
|
|
||||||
property color primaryHover: Qt.rgba(primary.r, primary.g, primary.b, 0.12)
|
property color primaryHover: Qt.rgba(primary.r, primary.g, primary.b, 0.12)
|
||||||
property color primaryHoverLight: Qt.rgba(primary.r, primary.g, primary.b, 0.08)
|
property color primaryHoverLight: Qt.rgba(primary.r, primary.g, primary.b, 0.08)
|
||||||
|
|||||||
@@ -308,109 +308,25 @@ QtObject {
|
|||||||
if (!group)
|
if (!group)
|
||||||
return
|
return
|
||||||
|
|
||||||
// Save current state for smart navigation
|
|
||||||
const currentGroupKey = group.key
|
|
||||||
const isNotification = currentItem.type === "notification"
|
|
||||||
const notificationIndex = currentItem.notificationIndex
|
|
||||||
const totalNotificationsInGroup = group.notifications ? group.notifications.length : 0
|
|
||||||
const isLastNotificationInGroup = isNotification
|
|
||||||
&& totalNotificationsInGroup === 1
|
|
||||||
const isLastNotificationInList = isNotification
|
|
||||||
&& notificationIndex === totalNotificationsInGroup - 1
|
|
||||||
|
|
||||||
// Store what to select next BEFORE clearing
|
|
||||||
let nextTargetType = ""
|
|
||||||
let nextTargetGroupKey = ""
|
|
||||||
let nextTargetNotificationIndex = -1
|
|
||||||
|
|
||||||
if (currentItem.type === "group") {
|
if (currentItem.type === "group") {
|
||||||
NotificationService.dismissGroup(group.key)
|
NotificationService.dismissGroup(group.key)
|
||||||
|
} else if (currentItem.type === "notification") {
|
||||||
// Look for next group
|
const notification = group.notifications[currentItem.notificationIndex]
|
||||||
for (var i = currentItem.groupIndex + 1; i < groups.length; i++) {
|
|
||||||
nextTargetType = "group"
|
|
||||||
nextTargetGroupKey = groups[i].key
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nextTargetGroupKey && currentItem.groupIndex > 0) {
|
|
||||||
nextTargetType = "group"
|
|
||||||
nextTargetGroupKey = groups[currentItem.groupIndex - 1].key
|
|
||||||
}
|
|
||||||
} else if (isNotification) {
|
|
||||||
const notification = group.notifications[notificationIndex]
|
|
||||||
NotificationService.dismissNotification(notification)
|
NotificationService.dismissNotification(notification)
|
||||||
|
|
||||||
if (isLastNotificationInGroup) {
|
|
||||||
for (var i = currentItem.groupIndex + 1; i < groups.length; i++) {
|
|
||||||
nextTargetType = "group"
|
|
||||||
nextTargetGroupKey = groups[i].key
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nextTargetGroupKey && currentItem.groupIndex > 0) {
|
|
||||||
nextTargetType = "group"
|
|
||||||
nextTargetGroupKey = groups[currentItem.groupIndex - 1].key
|
|
||||||
}
|
|
||||||
} else if (isLastNotificationInList) {
|
|
||||||
// If group still has notifications after this one is removed, select the new last one
|
|
||||||
if (group.count > 1) {
|
|
||||||
nextTargetType = "notification"
|
|
||||||
nextTargetGroupKey = currentGroupKey
|
|
||||||
// After removing current notification, the new last index will be count-2
|
|
||||||
nextTargetNotificationIndex = group.count - 2
|
|
||||||
} else {
|
|
||||||
// Group will be empty or collapsed, select the group header
|
|
||||||
nextTargetType = "group"
|
|
||||||
nextTargetGroupKey = currentGroupKey
|
|
||||||
nextTargetNotificationIndex = -1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nextTargetType = "notification"
|
|
||||||
nextTargetGroupKey = currentGroupKey
|
|
||||||
nextTargetNotificationIndex = notificationIndex
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuildFlatNavigation()
|
rebuildFlatNavigation()
|
||||||
|
|
||||||
// Find and select the target we identified
|
|
||||||
if (flatNavigation.length === 0) {
|
if (flatNavigation.length === 0) {
|
||||||
selectedFlatIndex = 0
|
keyboardNavigationActive = false
|
||||||
updateSelectedIdFromIndex()
|
if (listView) {
|
||||||
} else if (nextTargetGroupKey) {
|
listView.keyboardActive = false
|
||||||
let found = false
|
|
||||||
for (var i = 0; i < flatNavigation.length; i++) {
|
|
||||||
const item = flatNavigation[i]
|
|
||||||
|
|
||||||
if (nextTargetType === "group" && item.type === "group"
|
|
||||||
&& item.groupKey === nextTargetGroupKey) {
|
|
||||||
selectedFlatIndex = i
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
} else if (nextTargetType === "notification"
|
|
||||||
&& item.type === "notification"
|
|
||||||
&& item.groupKey === nextTargetGroupKey
|
|
||||||
&& item.notificationIndex === nextTargetNotificationIndex) {
|
|
||||||
selectedFlatIndex = i
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
selectedFlatIndex = Math.min(selectedFlatIndex,
|
|
||||||
flatNavigation.length - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSelectedIdFromIndex()
|
|
||||||
} else {
|
} else {
|
||||||
selectedFlatIndex = Math.min(selectedFlatIndex,
|
selectedFlatIndex = Math.min(selectedFlatIndex, flatNavigation.length - 1)
|
||||||
flatNavigation.length - 1)
|
|
||||||
updateSelectedIdFromIndex()
|
updateSelectedIdFromIndex()
|
||||||
|
ensureVisible()
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureVisible()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureVisible() {
|
function ensureVisible() {
|
||||||
|
|||||||
@@ -25,6 +25,17 @@ Singleton {
|
|||||||
property int seqCounter: 0
|
property int seqCounter: 0
|
||||||
property bool bulkDismissing: false
|
property bool bulkDismissing: false
|
||||||
|
|
||||||
|
property var _dismissQueue: []
|
||||||
|
property int _dismissBatchSize: 8
|
||||||
|
property int _dismissTickMs: 8
|
||||||
|
property bool _suspendGrouping: false
|
||||||
|
property var _groupCache: ({"notifications": [], "popups": []})
|
||||||
|
property bool _groupsDirty: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
_recomputeGroups()
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: addGate
|
id: addGate
|
||||||
interval: enterAnimMs + 50
|
interval: enterAnimMs + 50
|
||||||
@@ -47,11 +58,41 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: dismissPump
|
||||||
|
interval: _dismissTickMs
|
||||||
|
repeat: true
|
||||||
|
running: false
|
||||||
|
onTriggered: {
|
||||||
|
let n = Math.min(_dismissBatchSize, _dismissQueue.length)
|
||||||
|
for (let i = 0; i < n; ++i) {
|
||||||
|
const w = _dismissQueue.pop()
|
||||||
|
try {
|
||||||
|
if (w && w.notification) w.notification.dismiss()
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
if (_dismissQueue.length === 0) {
|
||||||
|
dismissPump.stop()
|
||||||
|
_suspendGrouping = false
|
||||||
|
bulkDismissing = false
|
||||||
|
popupsDisabled = false
|
||||||
|
_recomputeGroupsLater()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: groupsDebounce
|
||||||
|
interval: 16
|
||||||
|
repeat: false
|
||||||
|
onTriggered: _recomputeGroups()
|
||||||
|
}
|
||||||
|
|
||||||
property bool timeUpdateTick: false
|
property bool timeUpdateTick: false
|
||||||
property bool clockFormatChanged: false
|
property bool clockFormatChanged: false
|
||||||
|
|
||||||
readonly property var groupedNotifications: getGroupedNotifications()
|
readonly property var groupedNotifications: _groupCache.notifications
|
||||||
readonly property var groupedPopups: getGroupedPopups()
|
readonly property var groupedPopups: _groupCache.popups
|
||||||
|
|
||||||
property var expandedGroups: ({})
|
property var expandedGroups: ({})
|
||||||
property var expandedMessages: ({})
|
property var expandedMessages: ({})
|
||||||
@@ -89,6 +130,8 @@ Singleton {
|
|||||||
processQueue()
|
processQueue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_recomputeGroupsLater()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,12 +260,8 @@ Singleton {
|
|||||||
target: wrapper.notification.Retainable
|
target: wrapper.notification.Retainable
|
||||||
|
|
||||||
function onDropped(): void {
|
function onDropped(): void {
|
||||||
const notifIndex = root.notifications.indexOf(wrapper)
|
root.allWrappers = root.allWrappers.filter(w => w !== wrapper)
|
||||||
const allIndex = root.allWrappers.indexOf(wrapper)
|
root.notifications = root.notifications.filter(w => w !== wrapper)
|
||||||
if (allIndex !== -1)
|
|
||||||
root.allWrappers.splice(allIndex, 1)
|
|
||||||
if (notifIndex !== -1)
|
|
||||||
root.notifications.splice(notifIndex, 1)
|
|
||||||
|
|
||||||
if (root.bulkDismissing)
|
if (root.bulkDismissing)
|
||||||
return
|
return
|
||||||
@@ -236,6 +275,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanupExpansionStates()
|
cleanupExpansionStates()
|
||||||
|
root._recomputeGroupsLater()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAboutToDestroy(): void {
|
function onAboutToDestroy(): void {
|
||||||
@@ -256,30 +296,20 @@ Singleton {
|
|||||||
addGateBusy = false
|
addGateBusy = false
|
||||||
notificationQueue = []
|
notificationQueue = []
|
||||||
|
|
||||||
for (const w of visibleNotifications)
|
for (const w of allWrappers)
|
||||||
w.popup = false
|
w.popup = false
|
||||||
visibleNotifications = []
|
visibleNotifications = []
|
||||||
|
|
||||||
const toDismiss = notifications.slice()
|
_dismissQueue = notifications.slice()
|
||||||
|
|
||||||
if (notifications.length)
|
if (notifications.length)
|
||||||
notifications.splice(0, notifications.length)
|
notifications = []
|
||||||
expandedGroups = {}
|
expandedGroups = {}
|
||||||
expandedMessages = {}
|
expandedMessages = {}
|
||||||
|
|
||||||
for (var i = 0; i < toDismiss.length; ++i) {
|
_suspendGrouping = true
|
||||||
const w = toDismiss[i]
|
|
||||||
if (w && w.notification) {
|
|
||||||
try {
|
|
||||||
w.notification.dismiss()
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
}
|
if (!dismissPump.running && _dismissQueue.length)
|
||||||
}
|
dismissPump.start()
|
||||||
}
|
|
||||||
|
|
||||||
bulkDismissing = false
|
|
||||||
popupsDisabled = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dismissNotification(wrapper) {
|
function dismissNotification(wrapper) {
|
||||||
@@ -293,10 +323,10 @@ Singleton {
|
|||||||
popupsDisabled = disable
|
popupsDisabled = disable
|
||||||
if (disable) {
|
if (disable) {
|
||||||
notificationQueue = []
|
notificationQueue = []
|
||||||
visibleNotifications = []
|
for (const notif of visibleNotifications) {
|
||||||
for (const notif of root.allWrappers) {
|
|
||||||
notif.popup = false
|
notif.popup = false
|
||||||
}
|
}
|
||||||
|
visibleNotifications = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,32 +355,20 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeFromVisibleNotifications(wrapper) {
|
function removeFromVisibleNotifications(wrapper) {
|
||||||
const i = visibleNotifications.findIndex(n => n === wrapper)
|
visibleNotifications = visibleNotifications.filter(n => n !== wrapper)
|
||||||
if (i !== -1) {
|
processQueue()
|
||||||
const v = [...visibleNotifications]
|
|
||||||
v.splice(i, 1)
|
|
||||||
visibleNotifications = v
|
|
||||||
processQueue()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function releaseWrapper(w) {
|
function releaseWrapper(w) {
|
||||||
let v = visibleNotifications.slice()
|
visibleNotifications = visibleNotifications.filter(n => n !== w)
|
||||||
const vi = v.indexOf(w)
|
notificationQueue = notificationQueue.filter(n => n !== w)
|
||||||
if (vi !== -1) {
|
|
||||||
v.splice(vi, 1)
|
|
||||||
visibleNotifications = v
|
|
||||||
}
|
|
||||||
|
|
||||||
let q = notificationQueue.slice()
|
|
||||||
const qi = q.indexOf(w)
|
|
||||||
if (qi !== -1) {
|
|
||||||
q.splice(qi, 1)
|
|
||||||
notificationQueue = q
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w && w.destroy && !w.isPersistent) {
|
if (w && w.destroy && !w.isPersistent) {
|
||||||
w.destroy()
|
Qt.callLater(() => {
|
||||||
|
try {
|
||||||
|
w.destroy()
|
||||||
|
} catch (e) {}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +380,25 @@ Singleton {
|
|||||||
return wrapper.appName.toLowerCase()
|
return wrapper.appName.toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGroupedNotifications() {
|
function _recomputeGroups() {
|
||||||
|
if (_suspendGrouping) {
|
||||||
|
_groupsDirty = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_groupCache = {
|
||||||
|
"notifications": _calcGroupedNotifications(),
|
||||||
|
"popups": _calcGroupedPopups()
|
||||||
|
}
|
||||||
|
_groupsDirty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function _recomputeGroupsLater() {
|
||||||
|
_groupsDirty = true
|
||||||
|
if (!groupsDebounce.running)
|
||||||
|
groupsDebounce.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
function _calcGroupedNotifications() {
|
||||||
const groups = {}
|
const groups = {}
|
||||||
|
|
||||||
for (const notif of notifications) {
|
for (const notif of notifications) {
|
||||||
@@ -400,7 +436,7 @@ Singleton {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGroupedPopups() {
|
function _calcGroupedPopups() {
|
||||||
const groups = {}
|
const groups = {}
|
||||||
|
|
||||||
for (const notif of popups) {
|
for (const notif of popups) {
|
||||||
|
|||||||
207
spam-notifications.sh
Executable file
207
spam-notifications.sh
Executable file
@@ -0,0 +1,207 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Notification Spam Test Script - Sends 100 rapid notifications from fake apps
|
||||||
|
|
||||||
|
echo "NOTIFICATION SPAM TEST - 100 RAPID NOTIFICATIONS"
|
||||||
|
echo "============================================================="
|
||||||
|
echo "WARNING: This will send 100 notifications very quickly!"
|
||||||
|
echo "Press Ctrl+C to cancel, or wait 3 seconds to continue..."
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# Arrays of fake app names and icons
|
||||||
|
APPS=(
|
||||||
|
"slack:mail-message-new"
|
||||||
|
"discord:internet-chat"
|
||||||
|
"teams:call-start"
|
||||||
|
"zoom:camera-video"
|
||||||
|
"spotify:audio-x-generic"
|
||||||
|
"chrome:web-browser"
|
||||||
|
"firefox:web-browser"
|
||||||
|
"vscode:text-editor"
|
||||||
|
"terminal:utilities-terminal"
|
||||||
|
"steam:applications-games"
|
||||||
|
"telegram:internet-chat"
|
||||||
|
"whatsapp:phone"
|
||||||
|
"signal:security-high"
|
||||||
|
"thunderbird:mail-client"
|
||||||
|
"calendar:office-calendar"
|
||||||
|
"notes:text-editor"
|
||||||
|
"todo:emblem-default"
|
||||||
|
"weather:weather-few-clouds"
|
||||||
|
"news:rss"
|
||||||
|
"reddit:web-browser"
|
||||||
|
"twitter:internet-web-browser"
|
||||||
|
"instagram:camera-photo"
|
||||||
|
"youtube:video-x-generic"
|
||||||
|
"netflix:media-playback-start"
|
||||||
|
"github:folder-development"
|
||||||
|
"gitlab:folder-development"
|
||||||
|
"jira:applications-office"
|
||||||
|
"notion:text-editor"
|
||||||
|
"obsidian:accessories-text-editor"
|
||||||
|
"dropbox:folder-remote"
|
||||||
|
"gdrive:folder-google-drive"
|
||||||
|
"onedrive:folder-cloud"
|
||||||
|
"backup:drive-harddisk"
|
||||||
|
"antivirus:security-high"
|
||||||
|
"vpn:network-vpn"
|
||||||
|
"torrent:network-server"
|
||||||
|
"docker:application-x-executable"
|
||||||
|
"kubernetes:applications-system"
|
||||||
|
"postgres:database"
|
||||||
|
"mongodb:database"
|
||||||
|
"redis:database"
|
||||||
|
"nginx:network-server"
|
||||||
|
"apache:network-server"
|
||||||
|
"jenkins:applications-development"
|
||||||
|
"gradle:applications-development"
|
||||||
|
"maven:applications-development"
|
||||||
|
"npm:package-x-generic"
|
||||||
|
"yarn:package-x-generic"
|
||||||
|
"pip:package-x-generic"
|
||||||
|
"apt:system-software-install"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Arrays of message types
|
||||||
|
TITLES=(
|
||||||
|
"New message"
|
||||||
|
"Update available"
|
||||||
|
"Download complete"
|
||||||
|
"Task finished"
|
||||||
|
"Build successful"
|
||||||
|
"Deployment complete"
|
||||||
|
"Sync complete"
|
||||||
|
"Backup finished"
|
||||||
|
"Security alert"
|
||||||
|
"New notification"
|
||||||
|
"Process complete"
|
||||||
|
"Upload finished"
|
||||||
|
"Connection established"
|
||||||
|
"Meeting starting"
|
||||||
|
"Reminder"
|
||||||
|
"Warning"
|
||||||
|
"Error occurred"
|
||||||
|
"Success"
|
||||||
|
"Failed"
|
||||||
|
"Pending"
|
||||||
|
"In progress"
|
||||||
|
"Scheduled"
|
||||||
|
"New activity"
|
||||||
|
"Status update"
|
||||||
|
"Alert"
|
||||||
|
"Information"
|
||||||
|
"Breaking news"
|
||||||
|
"Hot update"
|
||||||
|
"Trending"
|
||||||
|
"New release"
|
||||||
|
)
|
||||||
|
|
||||||
|
MESSAGES=(
|
||||||
|
"Your request has been processed successfully"
|
||||||
|
"New content is available for download"
|
||||||
|
"Operation completed without errors"
|
||||||
|
"Check your inbox for updates"
|
||||||
|
"3 new items require your attention"
|
||||||
|
"Background task finished executing"
|
||||||
|
"All systems operational"
|
||||||
|
"Performance metrics updated"
|
||||||
|
"Configuration saved successfully"
|
||||||
|
"Database connection established"
|
||||||
|
"Cache cleared and rebuilt"
|
||||||
|
"Service restarted automatically"
|
||||||
|
"Logs have been rotated"
|
||||||
|
"Memory usage optimized"
|
||||||
|
"Network latency improved"
|
||||||
|
"Security scan completed - no threats"
|
||||||
|
"Automatic backup created"
|
||||||
|
"Files synchronized across devices"
|
||||||
|
"Updates installed successfully"
|
||||||
|
"New features are now available"
|
||||||
|
"Your subscription has been renewed"
|
||||||
|
"Report generated and ready"
|
||||||
|
"Analysis complete - view results"
|
||||||
|
"Queue processed: 42 items"
|
||||||
|
"Rate limit will reset in 5 minutes"
|
||||||
|
"API call successful (200 OK)"
|
||||||
|
"Webhook delivered successfully"
|
||||||
|
"Container started on port 8080"
|
||||||
|
"Build artifact uploaded"
|
||||||
|
"Test suite passed: 100/100"
|
||||||
|
"Coverage report: 95%"
|
||||||
|
"Dependencies updated to latest"
|
||||||
|
"Migration completed successfully"
|
||||||
|
"Index rebuilt for faster queries"
|
||||||
|
"SSL certificate renewed"
|
||||||
|
"Firewall rules updated"
|
||||||
|
"DNS propagation complete"
|
||||||
|
"CDN cache purged globally"
|
||||||
|
"Load balancer health check: OK"
|
||||||
|
"Cluster scaled to 5 nodes"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Urgency levels
|
||||||
|
URGENCY=("low" "normal")
|
||||||
|
|
||||||
|
# Counter
|
||||||
|
COUNT=0
|
||||||
|
TOTAL=100
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Starting notification spam..."
|
||||||
|
echo "------------------------------"
|
||||||
|
|
||||||
|
# Send notifications rapidly
|
||||||
|
for i in $(seq 1 $TOTAL); do
|
||||||
|
# Pick random app, title, message, and urgency
|
||||||
|
APP=${APPS[$RANDOM % ${#APPS[@]}]}
|
||||||
|
APP_NAME=${APP%%:*}
|
||||||
|
APP_ICON=${APP#*:}
|
||||||
|
TITLE=${TITLES[$RANDOM % ${#TITLES[@]}]}
|
||||||
|
MESSAGE=${MESSAGES[$RANDOM % ${#MESSAGES[@]}]}
|
||||||
|
URG=${URGENCY[$RANDOM % ${#URGENCY[@]}]}
|
||||||
|
|
||||||
|
# Add some variety with random numbers and timestamps
|
||||||
|
RAND_NUM=$((RANDOM % 1000))
|
||||||
|
TIMESTAMP=$(date +"%H:%M:%S")
|
||||||
|
|
||||||
|
# Randomly add extra details to some messages
|
||||||
|
if [ $((RANDOM % 3)) -eq 0 ]; then
|
||||||
|
MESSAGE="[$TIMESTAMP] $MESSAGE (#$RAND_NUM)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Send notification with very short delay
|
||||||
|
notify-send \
|
||||||
|
-h string:desktop-entry:$APP_NAME \
|
||||||
|
-i $APP_ICON \
|
||||||
|
-u $URG \
|
||||||
|
"$APP_NAME: $TITLE" \
|
||||||
|
"$MESSAGE" &
|
||||||
|
|
||||||
|
# Increment counter
|
||||||
|
COUNT=$((COUNT + 1))
|
||||||
|
|
||||||
|
# Show progress every 10 notifications
|
||||||
|
if [ $((COUNT % 10)) -eq 0 ]; then
|
||||||
|
echo " Sent $COUNT/$TOTAL notifications..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Tiny delay to prevent complete system freeze
|
||||||
|
# Adjust this value: smaller = faster spam, larger = slower spam
|
||||||
|
sleep 0.01
|
||||||
|
done
|
||||||
|
|
||||||
|
# Wait for all background notifications to complete
|
||||||
|
wait
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Spam test complete!"
|
||||||
|
echo "============================================================="
|
||||||
|
echo "Statistics:"
|
||||||
|
echo " Total notifications sent: $TOTAL"
|
||||||
|
echo " Apps simulated: ${#APPS[@]}"
|
||||||
|
echo " Message variations: ${#MESSAGES[@]}"
|
||||||
|
echo " Time taken: ~$(($TOTAL / 100)) seconds"
|
||||||
|
echo ""
|
||||||
|
echo "Check your notification center - it should be FULL!"
|
||||||
|
echo "Tip: You may want to clear all notifications after this test"
|
||||||
|
echo ""
|
||||||
Reference in New Issue
Block a user