Merge pull request #898 from oluijks/feat/notification-tabs

feat: add date-range tabs to the notification history panel
This commit is contained in:
Lysec
2025-11-29 08:22:28 +01:00
committed by GitHub
12 changed files with 202 additions and 12 deletions

View File

@@ -509,6 +509,12 @@
"no-notifications": "Keine Benachrichtigungen",
"title": "Benachrichtigungen"
},
"range": {
"all": "Alle",
"earlier": "Älter",
"today": "Heute",
"yesterday": "Gestern"
},
"time": {
"diffD": "vor 1 Tag",
"diffDD": "vor {diff} Tagen",

View File

@@ -509,6 +509,12 @@
"no-notifications": "No notifications",
"title": "Notifications"
},
"range": {
"all": "All",
"earlier": "Earlier",
"today": "Today",
"yesterday": "Yesterday"
},
"time": {
"diffD": "1 day ago",
"diffDD": "{diff} days ago",

View File

@@ -509,6 +509,12 @@
"no-notifications": "No hay notificaciones",
"title": "Notificaciones"
},
"range": {
"all": "Todas",
"earlier": "Anteriores",
"today": "Hoy",
"yesterday": "Ayer"
},
"time": {
"diffD": "hace 1 día",
"diffDD": "hace {diff} días",

View File

@@ -509,6 +509,12 @@
"no-notifications": "Aucune notification",
"title": "Notifications"
},
"range": {
"all": "Tout",
"earlier": "Plus anciennes",
"today": "Aujourd'hui",
"yesterday": "Hier"
},
"time": {
"diffD": "il y a 1 jour",
"diffDD": "il y a {diff} jours",

View File

@@ -509,6 +509,12 @@
"no-notifications": "通知なし",
"title": "通知"
},
"range": {
"all": "すべて",
"earlier": "以前",
"today": "今日",
"yesterday": "昨日"
},
"time": {
"diffD": "1日前",
"diffDD": "{diff}日前",

View File

@@ -509,6 +509,12 @@
"no-notifications": "Geen meldingen",
"title": "Meldingen"
},
"range": {
"all": "Alle",
"earlier": "Eerder",
"today": "Vandaag",
"yesterday": "Gisteren"
},
"time": {
"diffD": "1 dag geleden",
"diffDD": "{diff} dagen geleden",

View File

@@ -509,6 +509,12 @@
"no-notifications": "Nenhuma notificação",
"title": "Notificações"
},
"range": {
"all": "Todas",
"earlier": "Mais antigas",
"today": "Hoje",
"yesterday": "Ontem"
},
"time": {
"diffD": "há 1 dia",
"diffDD": "há {diff} dias",

View File

@@ -509,6 +509,12 @@
"no-notifications": "Нет уведомлений",
"title": "Уведомления"
},
"range": {
"all": "Все",
"earlier": "Ранее",
"today": "Сегодня",
"yesterday": "Вчера"
},
"time": {
"diffD": "1 день назад",
"diffDD": "{diff} дней назад",

View File

@@ -509,6 +509,12 @@
"no-notifications": "Bildirim yok",
"title": "Bildirimler"
},
"range": {
"all": "Tümü",
"earlier": "Öncekiler",
"today": "Bugün",
"yesterday": "Dün"
},
"time": {
"diffD": "1 gün önce",
"diffDD": "{diff} gün önce",

View File

@@ -509,6 +509,12 @@
"no-notifications": "Немає сповіщень",
"title": "Сповіщення"
},
"range": {
"all": "Усі",
"earlier": "Раніше",
"today": "Сьогодні",
"yesterday": "Учора"
},
"time": {
"diffD": "1 день тому",
"diffDD": "{diff} днів тому",

View File

@@ -509,6 +509,12 @@
"no-notifications": "无通知",
"title": "通知"
},
"range": {
"all": "全部",
"earlier": "更早",
"today": "今天",
"yesterday": "昨天"
},
"time": {
"diffD": "1 天前",
"diffDD": "{diff} 天前",

View File

@@ -13,6 +13,69 @@ import qs.Widgets
SmartPanel {
id: root
// 0 = All, 1 = Today, 2 = Yesterday, 3 = Earlier
property int currentRange: 1 // start on Today by default
property var rangeCounts: [0, 0, 0, 0]
property bool groupByDate: true
function dateOnly(d) {
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
}
function rangeForTimestamp(ts) {
var dt = new Date(ts);
var today = dateOnly(new Date());
var thatDay = dateOnly(dt);
var diffMs = today - thatDay;
var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffDays === 0)
return 0;
if (diffDays === 1)
return 1;
return 2;
}
function isInCurrentRange(ts) {
if (currentRange === 0)
return true;
return rangeForTimestamp(ts) === (currentRange - 1);
}
function recalcRangeCounts() {
var m = NotificationService.historyList;
if (!m || typeof m.count === "undefined" || m.count <= 0) {
rangeCounts = [0, 0, 0, 0];
return;
}
var counts = [0, 0, 0, 0];
counts[0] = m.count;
for (var i = 0; i < m.count; ++i) {
var item = m.get(i);
if (!item || typeof item.timestamp === "undefined")
continue;
var r = rangeForTimestamp(item.timestamp);
counts[r + 1] = counts[r + 1] + 1;
}
rangeCounts = counts;
}
function countForRange(range) {
return rangeCounts[range] || 0;
}
Connections {
target: NotificationService.historyList
function onCountChanged() { recalcRangeCounts(); }
}
Component.onCompleted: recalcRangeCounts()
preferredWidth: Math.round(420 * Style.uiScaleRatio)
preferredHeight: Math.round(540 * Style.uiScaleRatio)
@@ -82,6 +145,66 @@ SmartPanel {
}
}
// Time range tabs ([All] / [Today] / [Yesterday] / [Earlier])
NBox {
Layout.fillWidth: true
Layout.topMargin: Style.marginS
implicitHeight: timeTabs.implicitHeight + (Style.marginS * 2)
visible: NotificationService.historyList.count > 0 && root.groupByDate
RowLayout {
id: timeTabs
spacing: Style.marginXS
anchors.fill: parent
anchors.margins: Style.marginS
visible: NotificationService.historyList.count > 0
Repeater {
model: 4
delegate: NButton {
readonly property int rangeId: index
readonly property bool isActive: root.currentRange === rangeId
text: {
if (rangeId === 0)
return I18n.tr("notifications.range.all") +
" (" + root.countForRange(rangeId) + ")";
else if (rangeId === 1)
return I18n.tr("notifications.range.today") +
" (" + root.countForRange(rangeId) + ")";
else if (rangeId === 2)
return I18n.tr("notifications.range.yesterday") +
" (" + root.countForRange(rangeId) + ")";
return I18n.tr("notifications.range.earlier") +
" (" + root.countForRange(rangeId) + ")";
}
Layout.fillWidth: true
Layout.preferredWidth: 1
implicitHeight: Style.baseWidgetSize * 0.7
fontSize: Style.fontSizeXS
outlined: false
backgroundColor: isActive
? Color.mPrimary
: (hovered ? Color.mHover : Color.transparent)
textColor: isActive
? Color.mOnPrimary
: (hovered ? Color.mOnHover : Color.mOnSurface)
hoverColor: backgroundColor
Behavior on backgroundColor {
enabled: !Settings.data.general.animationDisabled
ColorAnimation { duration: Style.animationFast }
}
onClicked: root.currentRange = rangeId
}
}
}
}
// Empty state when no notifications
ColumnLayout {
Layout.fillWidth: true
@@ -148,7 +271,8 @@ SmartPanel {
delegate: Item {
id: notificationDelegate
width: parent.width
height: contentColumn.height + (Style.marginM * 2)
visible: root.isInCurrentRange(model.timestamp)
height: visible ? contentColumn.height + (Style.marginM * 2) : 0
property string notificationId: model.id
property bool isExpanded: scrollView.expandedId === notificationId