163 lines
4.8 KiB
Dart
163 lines
4.8 KiB
Dart
import 'dart:async';
|
||
import 'package:flutter/widgets.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import '../../core/di/injection.dart';
|
||
import '../../core/services/notification_service.dart';
|
||
import 'user_providers.dart';
|
||
|
||
/// ==================== 通知服务 Provider ====================
|
||
|
||
/// NotificationService 单例 Provider(从 GetIt 获取 ApiClient 构建)
|
||
final notificationServiceProvider = Provider<NotificationService>((ref) {
|
||
return NotificationService(apiClient: getIt());
|
||
});
|
||
|
||
/// ==================== 未读通知角标 ====================
|
||
|
||
/// 未读通知数量状态
|
||
class NotificationBadgeState {
|
||
final int unreadCount;
|
||
final bool isLoading;
|
||
|
||
const NotificationBadgeState({
|
||
this.unreadCount = 0,
|
||
this.isLoading = false,
|
||
});
|
||
|
||
NotificationBadgeState copyWith({
|
||
int? unreadCount,
|
||
bool? isLoading,
|
||
}) {
|
||
return NotificationBadgeState(
|
||
unreadCount: unreadCount ?? this.unreadCount,
|
||
isLoading: isLoading ?? this.isLoading,
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 未读通知数量管理器
|
||
///
|
||
/// 功能:
|
||
/// - 初始化时立即加载未读数量
|
||
/// - 每 30 秒自动轮询刷新
|
||
/// - 监听 App 生命周期,前台恢复时立即刷新
|
||
/// - 提供手动刷新、递减、清零方法供其他组件调用
|
||
///
|
||
/// 数据源:通过 [NotificationService.getUnreadCount] 调用后端 API
|
||
/// 用户标识:从 [currentAccountSequenceProvider] 获取当前登录用户的 accountSequence
|
||
class NotificationBadgeNotifier extends StateNotifier<NotificationBadgeState>
|
||
with WidgetsBindingObserver {
|
||
final NotificationService _notificationService;
|
||
final Ref _ref;
|
||
Timer? _refreshTimer;
|
||
|
||
/// 定时刷新间隔(30秒,与 1.0 一致)
|
||
static const _refreshIntervalSeconds = 30;
|
||
|
||
NotificationBadgeNotifier(this._notificationService, this._ref)
|
||
: super(const NotificationBadgeState()) {
|
||
// 监听 App 生命周期
|
||
WidgetsBinding.instance.addObserver(this);
|
||
// 初始化时立即加载未读数量
|
||
_loadUnreadCount();
|
||
// 启动定时刷新
|
||
_startAutoRefresh();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
WidgetsBinding.instance.removeObserver(this);
|
||
_refreshTimer?.cancel();
|
||
super.dispose();
|
||
}
|
||
|
||
/// App 从后台切回前台时立即刷新
|
||
@override
|
||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||
if (state == AppLifecycleState.resumed) {
|
||
debugPrint('[NotificationBadge] App 恢复前台,刷新未读数量');
|
||
_loadUnreadCount();
|
||
}
|
||
}
|
||
|
||
/// 启动 30 秒自动轮询
|
||
void _startAutoRefresh() {
|
||
_refreshTimer?.cancel();
|
||
_refreshTimer = Timer.periodic(
|
||
const Duration(seconds: _refreshIntervalSeconds),
|
||
(_) => _loadUnreadCount(),
|
||
);
|
||
debugPrint('[NotificationBadge] 自动刷新已启动 (间隔: ${_refreshIntervalSeconds}s)');
|
||
}
|
||
|
||
/// 停止自动刷新(账号切换时调用,避免混账号请求)
|
||
void stopAutoRefresh() {
|
||
_refreshTimer?.cancel();
|
||
_refreshTimer = null;
|
||
debugPrint('[NotificationBadge] 自动刷新已停止(切换账号)');
|
||
}
|
||
|
||
/// 从后端加载未读通知数量
|
||
Future<void> _loadUnreadCount() async {
|
||
try {
|
||
// 使用 2.0 的 currentAccountSequenceProvider 获取用户账号
|
||
final accountSequence = _ref.read(currentAccountSequenceProvider);
|
||
if (accountSequence == null || accountSequence.isEmpty) {
|
||
state = state.copyWith(unreadCount: 0);
|
||
return;
|
||
}
|
||
|
||
state = state.copyWith(isLoading: true);
|
||
|
||
final count = await _notificationService.getUnreadCount(
|
||
userSerialNum: accountSequence,
|
||
);
|
||
|
||
state = state.copyWith(
|
||
unreadCount: count,
|
||
isLoading: false,
|
||
);
|
||
|
||
debugPrint('[NotificationBadge] 未读通知数量: $count');
|
||
} catch (e) {
|
||
debugPrint('[NotificationBadge] 加载未读数量失败: $e');
|
||
state = state.copyWith(isLoading: false);
|
||
}
|
||
}
|
||
|
||
/// 手动刷新未读数量
|
||
Future<void> refresh() async {
|
||
await _loadUnreadCount();
|
||
}
|
||
|
||
/// 更新未读数量(本地同步)
|
||
void updateCount(int count) {
|
||
state = state.copyWith(unreadCount: count);
|
||
}
|
||
|
||
/// 减少未读数量(标记单条已读后调用)
|
||
void decrementCount() {
|
||
if (state.unreadCount > 0) {
|
||
state = state.copyWith(unreadCount: state.unreadCount - 1);
|
||
}
|
||
}
|
||
|
||
/// 清空未读数量(全部标记已读后调用)
|
||
void clearCount() {
|
||
state = state.copyWith(unreadCount: 0);
|
||
}
|
||
}
|
||
|
||
/// 未读通知角标 Provider
|
||
final notificationBadgeProvider =
|
||
StateNotifierProvider<NotificationBadgeNotifier, NotificationBadgeState>(
|
||
(ref) {
|
||
final notificationService = ref.watch(notificationServiceProvider);
|
||
return NotificationBadgeNotifier(notificationService, ref);
|
||
});
|
||
|
||
/// 便捷 Provider: 只获取未读数量(供 UI 直接使用)
|
||
final unreadNotificationCountProvider = Provider<int>((ref) {
|
||
return ref.watch(notificationBadgeProvider).unreadCount;
|
||
});
|