feat(client): notices api + provider(未读计数/markAllRead/延迟首拉)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// notices_provider.dart — 系统通知状态装配:复用 apiClientProvider,未登录不打网络。
|
||||
//
|
||||
// 对照 invite_provider.dart(装配模式:未登录 build 返回 null、不打网络)与
|
||||
// update_provider.dart(延迟首拉的可取消 Timer 模式)。回前台重拉由 Task 10 的
|
||||
// 消费方(WidgetsBindingObserver)调用 refresh(),本 provider 只暴露 refresh()。
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../services/notices_api.dart';
|
||||
import 'account_providers.dart';
|
||||
import 'auth_provider.dart';
|
||||
|
||||
/// 首次拉取前的延迟(避开登录/首屏竞争)。
|
||||
const _kInitialDelay = Duration(seconds: 2);
|
||||
|
||||
final noticesApiProvider = Provider<NoticesApi>((ref) => NoticesApi(ref.watch(apiClientProvider)));
|
||||
|
||||
class NoticesNotifier extends AsyncNotifier<NoticesData?> {
|
||||
Timer? _initialTimer;
|
||||
|
||||
@override
|
||||
Future<NoticesData?> build() async {
|
||||
ref.onDispose(() => _initialTimer?.cancel());
|
||||
|
||||
// 未登录返回 null(不打网络)。
|
||||
final token = ref.watch(authProvider).accessToken;
|
||||
if (token == null || token.isEmpty) return null;
|
||||
|
||||
// 延迟首拉:用可取消的 Timer(而非 Future.delayed,其内部 timer 无法取消,
|
||||
// provider 在延迟期间被 dispose 时会悬挂)。
|
||||
final ready = Completer<void>();
|
||||
_initialTimer = Timer(_kInitialDelay, ready.complete);
|
||||
await ready.future; // 若延迟期间被 dispose,_initialTimer 取消 → 永不 complete,build 中止
|
||||
|
||||
return ref.read(noticesApiProvider).fetch();
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => ref.read(noticesApiProvider).fetch());
|
||||
}
|
||||
|
||||
/// 标记全部已读:调服务端成功后,本地把 unreadCount 置 0、items 的 unread 置 false。
|
||||
Future<void> markAllRead() async {
|
||||
final current = state.value;
|
||||
if (current == null) return;
|
||||
await ref.read(noticesApiProvider).markRead();
|
||||
state = AsyncValue.data(current.copyWith(
|
||||
items: current.items.map((n) => n.copyWith(unread: false)).toList(),
|
||||
unreadCount: 0,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
final noticesProvider = AsyncNotifierProvider<NoticesNotifier, NoticesData?>(NoticesNotifier.new);
|
||||
Reference in New Issue
Block a user