Reactive notification unread count

This commit is contained in:
LittleSheep 2025-05-28 01:52:44 +08:00
parent bfa97dcd11
commit 9c1a983466
2 changed files with 30 additions and 16 deletions

View File

@ -51,8 +51,8 @@ class WebSocketService {
Future<void> connect(Ref ref) async { Future<void> connect(Ref ref) async {
_ref = ref; _ref = ref;
_statusStreamController.sink.add(WebSocketState.connecting()); _statusStreamController.sink.add(WebSocketState.connecting());
final baseUrl = ref.watch(serverUrlProvider); final baseUrl = ref.watch(serverUrlProvider);
final atk = await getFreshAtk( final atk = await getFreshAtk(
ref.watch(tokenPairProvider), ref.watch(tokenPairProvider),
@ -141,19 +141,6 @@ class WebSocketStateNotifier extends StateNotifier<WebSocketState> {
state = const WebSocketState.connecting(); state = const WebSocketState.connecting();
try { try {
final service = ref.read(websocketProvider); final service = ref.read(websocketProvider);
final baseUrl = ref.watch(serverUrlProvider);
final atk = await getFreshAtk(
ref.watch(tokenPairProvider),
baseUrl,
onRefreshed: (atk, rtk) {
setTokenPair(ref.watch(sharedPreferencesProvider), atk, rtk);
ref.invalidate(tokenPairProvider);
},
);
if (atk == null) {
state = const WebSocketState.error('Unauthorized');
return;
}
await service.connect(ref); await service.connect(ref);
state = const WebSocketState.connected(); state = const WebSocketState.connected();
service.statusStream.listen((event) { service.statusStream.listen((event) {

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:math' as math; import 'dart:math' as math;
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
@ -7,6 +8,7 @@ import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/user.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/websocket.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/markdown.dart'; import 'package:island/widgets/content/markdown.dart';
@ -21,8 +23,18 @@ part 'notification.g.dart';
@riverpod @riverpod
class NotificationUnreadCountNotifier class NotificationUnreadCountNotifier
extends _$NotificationUnreadCountNotifier { extends _$NotificationUnreadCountNotifier {
StreamSubscription<WebSocketPacket>? _subscription;
@override @override
Future<int> build() async { Future<int> build() async {
// Subscribe to websocket events when this provider is built
_subscribeToWebSocket();
// Dispose the subscription when this provider is disposed
ref.onDispose(() {
_subscription?.cancel();
});
try { try {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
final response = await client.get('/notifications/count'); final response = await client.get('/notifications/count');
@ -32,9 +44,23 @@ class NotificationUnreadCountNotifier
} }
} }
void _subscribeToWebSocket() {
final webSocketService = ref.read(websocketProvider);
_subscription = webSocketService.dataStream.listen((packet) {
if (packet.type == 'notifications.new') {
_incrementCounter();
}
});
}
Future<void> _incrementCounter() async {
final current = await future;
state = AsyncData(current + 1);
}
Future<void> decrement(int count) async { Future<void> decrement(int count) async {
final current = await future; final current = await future;
state = AsyncData(math.min(current - count, 0)); state = AsyncData(math.max(current - count, 0));
} }
} }
@ -94,6 +120,7 @@ class NotificationScreen extends HookConsumerWidget {
notifierRefreshable: notificationListNotifierProvider.notifier, notifierRefreshable: notificationListNotifierProvider.notifier,
contentBuilder: contentBuilder:
(data, widgetCount, endItemView) => ListView.builder( (data, widgetCount, endItemView) => ListView.builder(
padding: EdgeInsets.zero,
itemCount: widgetCount, itemCount: widgetCount,
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (index == widgetCount - 1) { if (index == widgetCount - 1) {
@ -142,7 +169,7 @@ class NotificationScreen extends HookConsumerWidget {
], ],
), ),
trailing: trailing:
notification.viewedAt == null notification.viewedAt != null
? null ? null
: Container( : Container(
width: 12, width: 12,