rwadurian/frontend/mining-app/lib/presentation/providers/notification_providers.dart

163 lines
4.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
});