91 lines
2.8 KiB
Dart
91 lines
2.8 KiB
Dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../../../../core/config/app_config.dart';
|
|
import '../../../../core/services/notification_service.dart';
|
|
import '../../domain/entities/app_notification.dart';
|
|
import '../../data/in_site_notification.dart';
|
|
import '../../data/in_site_notification_repository.dart';
|
|
|
|
/// Global local notifications plugin instance (initialized in main.dart).
|
|
final localNotificationsPluginProvider =
|
|
Provider<FlutterLocalNotificationsPlugin>((ref) {
|
|
return FlutterLocalNotificationsPlugin();
|
|
});
|
|
|
|
/// Notification service singleton.
|
|
final notificationServiceProvider = Provider<NotificationService>((ref) {
|
|
final config = ref.watch(appConfigProvider);
|
|
final plugin = ref.watch(localNotificationsPluginProvider);
|
|
return NotificationService(
|
|
baseUrl: config.apiBaseUrl,
|
|
localNotifications: plugin,
|
|
);
|
|
});
|
|
|
|
/// Accumulated push notification list (local/realtime).
|
|
class NotificationListNotifier extends StateNotifier<List<AppNotification>> {
|
|
NotificationListNotifier() : super([]);
|
|
|
|
void add(AppNotification notification) {
|
|
state = [notification, ...state];
|
|
}
|
|
|
|
void markRead(String id) {
|
|
state = state.map((n) {
|
|
if (n.id == id) return n.copyWith(isRead: true);
|
|
return n;
|
|
}).toList();
|
|
}
|
|
|
|
void markAllRead() {
|
|
state = state.map((n) => n.copyWith(isRead: true)).toList();
|
|
}
|
|
|
|
void clear() {
|
|
state = [];
|
|
}
|
|
}
|
|
|
|
final notificationListProvider =
|
|
StateNotifierProvider<NotificationListNotifier, List<AppNotification>>(
|
|
(ref) {
|
|
return NotificationListNotifier();
|
|
});
|
|
|
|
/// Local push notification unread count.
|
|
final unreadNotificationCountProvider = Provider<int>((ref) {
|
|
final notifications = ref.watch(notificationListProvider);
|
|
return notifications.where((n) => !n.isRead).length;
|
|
});
|
|
|
|
// ── In-site (站内消息) notification providers ──────────────────────────────
|
|
|
|
/// Polls the backend every 30s for the unread in-site notification count.
|
|
final inSiteUnreadCountProvider = StreamProvider<int>((ref) async* {
|
|
final repo = ref.watch(inSiteNotificationRepositoryProvider);
|
|
|
|
Future<int> fetch() async {
|
|
try {
|
|
return await repo.getUnreadCount();
|
|
} catch (_) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Emit immediately on first build
|
|
yield await fetch();
|
|
|
|
// Then poll every 30s
|
|
await for (final _ in Stream.periodic(const Duration(seconds: 30))) {
|
|
yield await fetch();
|
|
}
|
|
});
|
|
|
|
/// Fetches the full in-site notification list (on demand, refreshed when invalidated).
|
|
final inSiteNotificationsProvider =
|
|
FutureProvider<List<InSiteNotification>>((ref) async {
|
|
final repo = ref.watch(inSiteNotificationRepositoryProvider);
|
|
final result = await repo.getMyNotifications(limit: 100);
|
|
return result.items;
|
|
});
|