Add per-server notification handling with server-specific enable/disable logic and message count in notifications.

This commit is contained in:
akastijn 2026-07-19 18:46:46 +02:00
parent b415d2968d
commit 915b64cdb0
3 changed files with 52 additions and 15 deletions

View File

@ -1,4 +1,4 @@
import {Component, inject, input} from '@angular/core'; import {Component, computed, inject, input} from '@angular/core';
import {getServerColor, getServerTextColor} from '@pages/altitude/chat/util/server-color'; import {getServerColor, getServerTextColor} from '@pages/altitude/chat/util/server-color';
import {NotificationService} from '@pages/altitude/chat/service/chat-notification.service'; import {NotificationService} from '@pages/altitude/chat/service/chat-notification.service';
import {NotificationEnabledSvgComponent} from '@pages/altitude/chat/svg/notification-enabled.svg'; import {NotificationEnabledSvgComponent} from '@pages/altitude/chat/svg/notification-enabled.svg';
@ -17,20 +17,20 @@ export class ChatInfoComponent {
private readonly notificationService: NotificationService = inject(NotificationService); private readonly notificationService: NotificationService = inject(NotificationService);
public readonly selectedServer = input.required<string>(); public readonly selectedServer = input.required<string>();
protected readonly notificationEnabled = this.notificationService.notificationEnabled; protected readonly notificationEnabled = computed(() => this.notificationService.isNotificationEnabled(this.selectedServer()));
protected readonly getServerColor = getServerColor; protected readonly getServerColor = getServerColor;
protected readonly getServerTextColor = getServerTextColor; protected readonly getServerTextColor = getServerTextColor;
public enableNotifications() { public enableNotifications() {
this.notificationService.requestPermission().then( this.notificationService.requestPermission().then(
() => { () => {
this.notificationService.enableNotifications(); this.notificationService.enableNotifications(this.selectedServer());
} }
); );
} }
public disableNotifications() { public disableNotifications() {
this.notificationService.disableNotifications(); this.notificationService.disableNotifications(this.selectedServer());
} }
} }

View File

@ -5,8 +5,8 @@ export class NotificationService {
private readonly notificationSound = new Audio('/public/sounds/notification.mp3'); private readonly notificationSound = new Audio('/public/sounds/notification.mp3');
private readonly notificationStorageKey = 'chat-notifications-enabled'; private readonly notificationStorageKey = 'chat-notifications-enabled';
private readonly _notificationEnabled = signal<boolean>( private readonly _notificationEnabled = signal<Record<string, boolean>>(
localStorage.getItem(this.notificationStorageKey) === 'true' this.getStoredNotificationSettings()
); );
public readonly notificationEnabled = this._notificationEnabled.asReadonly(); public readonly notificationEnabled = this._notificationEnabled.asReadonly();
@ -33,8 +33,8 @@ export class NotificationService {
return false; return false;
} }
notify(title: string, body: string | null) { notify(server: string, title: string, body: string | null) {
if (!this.notificationEnabled()) { if (!this.isNotificationEnabled(server)) {
return; return;
} }
if (Notification.permission === 'granted') { if (Notification.permission === 'granted') {
@ -68,13 +68,43 @@ export class NotificationService {
}); });
} }
enableNotifications() { public isNotificationEnabled(server: string): boolean {
this._notificationEnabled.set(true); return this._notificationEnabled()[server];
localStorage.setItem(this.notificationStorageKey, 'true');
} }
disableNotifications() { enableNotifications(server: string) {
this._notificationEnabled.set(false); this.setNotificationEnabled(server, true);
localStorage.setItem(this.notificationStorageKey, 'false'); }
disableNotifications(server: string) {
this.setNotificationEnabled(server, false);
}
private setNotificationEnabled(server: string, enabled: boolean) {
const notificationSettings = {
...this._notificationEnabled(),
[server]: enabled
};
this._notificationEnabled.set(notificationSettings);
localStorage.setItem(this.notificationStorageKey, JSON.stringify(notificationSettings));
}
private getStoredNotificationSettings(): Record<string, boolean> {
const storedSettings = localStorage.getItem(this.notificationStorageKey);
if (storedSettings === null) {
return {};
}
if (storedSettings === 'true' || storedSettings === 'false') {
return {};
}
try {
return JSON.parse(storedSettings) as Record<string, boolean>;
} catch {
return {};
}
} }
} }

View File

@ -60,7 +60,14 @@ export class ChatService implements OnDestroy {
find.unreadMessages++; find.unreadMessages++;
} }
}) })
this.notificationService.notify(`(${chatMessages.length}) new messages`, null); const messagesByServer = chatMessages.reduce<Record<string, number>>((acc, message) => {
acc[message.server] = (acc[message.server] ?? 0) + 1;
return acc;
}, {});
Object.entries(messagesByServer).forEach(([server, messageCount]) => {
this.notificationService.notify(server, `New messages`, `(${messageCount}) new messages in ${server}`);
});
}); });
source.onerror = (err) => { source.onerror = (err) => {