feat: Add comprehensive notification system including model, UI, and service integration, alongside new deployment documentation.

This commit is contained in:
Patrick Britton 2026-02-04 12:17:58 -06:00
parent 13feb70356
commit 3f3e228e8a
4 changed files with 18 additions and 2 deletions

View file

@ -67,6 +67,7 @@ class _sojornAppState extends ConsumerState<sojornApp> {
void dispose() { void dispose() {
_linkSub?.cancel(); _linkSub?.cancel();
_authSub?.cancel(); _authSub?.cancel();
_notificationSub?.cancel();
_syncManager?.dispose(); _syncManager?.dispose();
super.dispose(); super.dispose();
} }
@ -115,6 +116,7 @@ class _sojornAppState extends ConsumerState<sojornApp> {
void _initNotifications() { void _initNotifications() {
if (_authService.isAuthenticated) { if (_authService.isAuthenticated) {
NotificationService.instance.init(); NotificationService.instance.init();
_listenForNotifications();
} }
} }
@ -147,6 +149,19 @@ class _sojornAppState extends ConsumerState<sojornApp> {
_syncManager!.init(); _syncManager!.init();
} }
StreamSubscription? _notificationSub;
void _listenForNotifications() {
_notificationSub?.cancel();
_notificationSub =
NotificationService.instance.foregroundMessages.listen((message) {
final context = AppRoutes.rootNavigatorKey.currentContext;
if (context != null) {
NotificationService.instance.showNotificationBanner(context, message);
}
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final themeMode = ref.watch(theme_provider.themeProvider); final themeMode = ref.watch(theme_provider.themeProvider);

View file

@ -58,7 +58,7 @@ class AppNotification {
id: json['id'] as String, id: json['id'] as String,
type: NotificationType.values.firstWhere( type: NotificationType.values.firstWhere(
(e) => e.name == json['type'], (e) => e.name == json['type'],
orElse: () => NotificationType.appreciate, orElse: () => NotificationType.like,
), ),
actor: json['actor'] != null actor: json['actor'] != null
? Profile.fromJson(json['actor'] as Map<String, dynamic>) ? Profile.fromJson(json['actor'] as Map<String, dynamic>)

View file

@ -10,6 +10,7 @@ import '../../widgets/app_scaffold.dart';
import '../../widgets/media/signed_media_image.dart'; import '../../widgets/media/signed_media_image.dart';
import '../profile/viewable_profile_screen.dart'; import '../profile/viewable_profile_screen.dart';
import '../post/post_detail_screen.dart'; import '../post/post_detail_screen.dart';
import 'package:go_router/go_router.dart';
/// Notifications screen showing user activity /// Notifications screen showing user activity
class NotificationsScreen extends ConsumerStatefulWidget { class NotificationsScreen extends ConsumerStatefulWidget {

View file

@ -199,7 +199,7 @@ Group=patrick
WorkingDirectory=/opt/sojorn/go-backend WorkingDirectory=/opt/sojorn/go-backend
Environment=GO_ENV=production Environment=GO_ENV=production
EnvironmentFile=/opt/sojorn/.env EnvironmentFile=/opt/sojorn/.env
ExecStart=/opt/sojorn/go-backend/bin/api ExecStart=/opt/sojorn/bin/api
Restart=always Restart=always
RestartSec=5 RestartSec=5
StandardOutput=journal StandardOutput=journal