mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 14:05:38 -05:00
294 lines
9.4 KiB
QML
294 lines
9.4 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
// Grouped notifications model
|
|
property var groupedNotifications: ListModel {}
|
|
|
|
// Total count of all notifications across all groups
|
|
property int totalCount: 0
|
|
|
|
// Map to track group indices by app name for efficient lookups
|
|
property var appGroupMap: ({})
|
|
|
|
// Configuration
|
|
property int maxNotificationsPerGroup: 10
|
|
property int maxGroups: 20
|
|
|
|
Component.onCompleted: {
|
|
groupedNotifications = Qt.createQmlObject(`
|
|
import QtQuick
|
|
ListModel {}
|
|
`, root)
|
|
}
|
|
|
|
// Format timestamp for display
|
|
function formatTimestamp(timestamp) {
|
|
if (!timestamp) return ""
|
|
|
|
const now = new Date()
|
|
const notifTime = new Date(timestamp)
|
|
const diffMs = now.getTime() - notifTime.getTime()
|
|
const diffMinutes = Math.floor(diffMs / 60000)
|
|
const diffHours = Math.floor(diffMs / 3600000)
|
|
const diffDays = Math.floor(diffMs / 86400000)
|
|
|
|
if (diffMinutes < 1) {
|
|
return "now"
|
|
} else if (diffMinutes < 60) {
|
|
return `${diffMinutes}m ago`
|
|
} else if (diffHours < 24) {
|
|
return `${diffHours}h ago`
|
|
} else if (diffDays < 7) {
|
|
return `${diffDays}d ago`
|
|
} else {
|
|
return notifTime.toLocaleDateString()
|
|
}
|
|
}
|
|
|
|
// Add a new notification to the appropriate group
|
|
function addNotification(notificationObj) {
|
|
if (!notificationObj || !notificationObj.appName) {
|
|
console.warn("Invalid notification object:", notificationObj)
|
|
return
|
|
}
|
|
|
|
const appName = notificationObj.appName
|
|
let groupIndex = appGroupMap[appName]
|
|
|
|
if (groupIndex === undefined) {
|
|
// Create new group
|
|
groupIndex = createNewGroup(appName, notificationObj)
|
|
} else {
|
|
// Add to existing group
|
|
addToExistingGroup(groupIndex, notificationObj)
|
|
}
|
|
|
|
updateTotalCount()
|
|
}
|
|
|
|
// Create a new notification group
|
|
function createNewGroup(appName, notificationObj) {
|
|
// Check if we need to remove oldest group
|
|
if (groupedNotifications.count >= maxGroups) {
|
|
removeOldestGroup()
|
|
}
|
|
|
|
const groupIndex = groupedNotifications.count
|
|
const notificationsList = Qt.createQmlObject(`
|
|
import QtQuick
|
|
ListModel {}
|
|
`, root)
|
|
|
|
notificationsList.append(notificationObj)
|
|
|
|
groupedNotifications.append({
|
|
"appName": appName,
|
|
"appIcon": notificationObj.appIcon || "",
|
|
"notifications": notificationsList,
|
|
"totalCount": 1,
|
|
"latestNotification": notificationObj,
|
|
"expanded": false,
|
|
"timestamp": notificationObj.timestamp
|
|
})
|
|
|
|
appGroupMap[appName] = groupIndex
|
|
updateGroupMap()
|
|
|
|
return groupIndex
|
|
}
|
|
|
|
// Add notification to existing group
|
|
function addToExistingGroup(groupIndex, notificationObj) {
|
|
if (groupIndex >= groupedNotifications.count) {
|
|
console.warn("Invalid group index:", groupIndex)
|
|
return
|
|
}
|
|
|
|
const group = groupedNotifications.get(groupIndex)
|
|
if (!group) return
|
|
|
|
// Add to front of group (newest first)
|
|
group.notifications.insert(0, notificationObj)
|
|
|
|
// Update group metadata
|
|
groupedNotifications.setProperty(groupIndex, "totalCount", group.totalCount + 1)
|
|
groupedNotifications.setProperty(groupIndex, "latestNotification", notificationObj)
|
|
groupedNotifications.setProperty(groupIndex, "timestamp", notificationObj.timestamp)
|
|
|
|
// Keep only max notifications per group
|
|
while (group.notifications.count > maxNotificationsPerGroup) {
|
|
group.notifications.remove(group.notifications.count - 1)
|
|
}
|
|
|
|
// Move group to front (most recent activity)
|
|
moveGroupToFront(groupIndex)
|
|
}
|
|
|
|
// Move a group to the front of the list
|
|
function moveGroupToFront(groupIndex) {
|
|
if (groupIndex === 0) return // Already at front
|
|
|
|
const group = groupedNotifications.get(groupIndex)
|
|
if (!group) return
|
|
|
|
// Remove from current position
|
|
groupedNotifications.remove(groupIndex)
|
|
|
|
// Insert at front
|
|
groupedNotifications.insert(0, group)
|
|
|
|
// Update group map
|
|
updateGroupMap()
|
|
}
|
|
|
|
// Remove the oldest group (least recent activity)
|
|
function removeOldestGroup() {
|
|
if (groupedNotifications.count === 0) return
|
|
|
|
const lastIndex = groupedNotifications.count - 1
|
|
const group = groupedNotifications.get(lastIndex)
|
|
if (group) {
|
|
delete appGroupMap[group.appName]
|
|
groupedNotifications.remove(lastIndex)
|
|
updateGroupMap()
|
|
}
|
|
}
|
|
|
|
// Update the app group map after structural changes
|
|
function updateGroupMap() {
|
|
appGroupMap = {}
|
|
for (let i = 0; i < groupedNotifications.count; i++) {
|
|
const group = groupedNotifications.get(i)
|
|
if (group) {
|
|
appGroupMap[group.appName] = i
|
|
}
|
|
}
|
|
}
|
|
|
|
// Toggle group expansion state
|
|
function toggleGroupExpansion(groupIndex) {
|
|
if (groupIndex >= groupedNotifications.count) return
|
|
|
|
const group = groupedNotifications.get(groupIndex)
|
|
if (group) {
|
|
groupedNotifications.setProperty(groupIndex, "expanded", !group.expanded)
|
|
}
|
|
}
|
|
|
|
// Remove a specific notification from a group
|
|
function removeNotification(groupIndex, notificationIndex) {
|
|
if (groupIndex >= groupedNotifications.count) return
|
|
|
|
const group = groupedNotifications.get(groupIndex)
|
|
if (!group || notificationIndex >= group.notifications.count) return
|
|
|
|
group.notifications.remove(notificationIndex)
|
|
|
|
// Update group count
|
|
const newCount = group.totalCount - 1
|
|
groupedNotifications.setProperty(groupIndex, "totalCount", newCount)
|
|
|
|
// If group is empty, remove it
|
|
if (newCount === 0) {
|
|
removeGroup(groupIndex)
|
|
} else {
|
|
// Update latest notification if we removed the latest one
|
|
if (notificationIndex === 0 && group.notifications.count > 0) {
|
|
const newLatest = group.notifications.get(0)
|
|
groupedNotifications.setProperty(groupIndex, "latestNotification", newLatest)
|
|
}
|
|
}
|
|
|
|
updateTotalCount()
|
|
}
|
|
|
|
// Remove an entire group
|
|
function removeGroup(groupIndex) {
|
|
if (groupIndex >= groupedNotifications.count) return
|
|
|
|
const group = groupedNotifications.get(groupIndex)
|
|
if (group) {
|
|
delete appGroupMap[group.appName]
|
|
groupedNotifications.remove(groupIndex)
|
|
updateGroupMap()
|
|
updateTotalCount()
|
|
}
|
|
}
|
|
|
|
// Clear all notifications
|
|
function clearAllNotifications() {
|
|
groupedNotifications.clear()
|
|
appGroupMap = {}
|
|
totalCount = 0
|
|
}
|
|
|
|
// Update total count across all groups
|
|
function updateTotalCount() {
|
|
let count = 0
|
|
for (let i = 0; i < groupedNotifications.count; i++) {
|
|
const group = groupedNotifications.get(i)
|
|
if (group) {
|
|
count += group.totalCount
|
|
}
|
|
}
|
|
totalCount = count
|
|
}
|
|
|
|
// Get notification by ID across all groups
|
|
function getNotificationById(notificationId) {
|
|
for (let i = 0; i < groupedNotifications.count; i++) {
|
|
const group = groupedNotifications.get(i)
|
|
if (!group) continue
|
|
|
|
for (let j = 0; j < group.notifications.count; j++) {
|
|
const notification = group.notifications.get(j)
|
|
if (notification && notification.id === notificationId) {
|
|
return {
|
|
groupIndex: i,
|
|
notificationIndex: j,
|
|
notification: notification
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
// Get group by app name
|
|
function getGroupByAppName(appName) {
|
|
const groupIndex = appGroupMap[appName]
|
|
if (groupIndex !== undefined) {
|
|
return {
|
|
groupIndex: groupIndex,
|
|
group: groupedNotifications.get(groupIndex)
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
// Get visible notifications for a group (considering expansion state)
|
|
function getVisibleNotifications(groupIndex, maxVisible = 3) {
|
|
if (groupIndex >= groupedNotifications.count) return []
|
|
|
|
const group = groupedNotifications.get(groupIndex)
|
|
if (!group) return []
|
|
|
|
if (group.expanded) {
|
|
// Show all notifications when expanded
|
|
return group.notifications
|
|
} else {
|
|
// Show only the latest notification(s) when collapsed
|
|
const visibleCount = Math.min(maxVisible, group.notifications.count)
|
|
const visible = []
|
|
for (let i = 0; i < visibleCount; i++) {
|
|
visible.push(group.notifications.get(i))
|
|
}
|
|
return visible
|
|
}
|
|
}
|
|
} |