flutter_integrated_whb/lib/pages/badge_manager.dart

246 lines
9.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_new_badger/flutter_new_badger.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:flutter/material.dart';
/// 优化版 BadgeManager每个接口超时保护、增量更新、notify 合并、原生角标 debounce
class BadgeManager extends ChangeNotifier {
BadgeManager._internal();
static final BadgeManager _instance = BadgeManager._internal();
factory BadgeManager() => _instance;
// 各模块未读
int _appCount = 0;
int _appDysCount = 0;
int _appDzgCount = 0;
int _notifCount = 0;
int _envInspectCount = 0;
int _eightWorkCount = 0;
// 读取接口值的公开 getter
int get count => _appCount + _notifCount + _envInspectCount + _eightWorkCount;
int get appCount => _appCount;
int get appDysCount => _appDysCount;
int get appDzgCount => _appDzgCount;
int get notifCount => _notifCount;
int get envInspectCount => _envInspectCount;
int get eightWorkCount => _eightWorkCount;
// 通知合并控制(短时间内多次更新只触发一次 notify
Timer? _notifyTimer;
Duration _notifyDelay = const Duration(milliseconds: 180);
void _scheduleNotify() {
// 如果已有计划,不需要再立即计划(合并)
_notifyTimer?.cancel();
_notifyTimer = Timer(_notifyDelay, () {
try {
notifyListeners();
} catch (e) {
debugPrint('BadgeManager.notifyListeners error: $e');
}
_notifyTimer = null;
});
}
// 原生角标同步 debounce防止短时间内频繁调用
Timer? _syncTimer;
Duration _syncDelay = const Duration(milliseconds: 250);
void _syncNativeDebounced() {
_syncTimer?.cancel();
_syncTimer = Timer(_syncDelay, () {
try {
final total = count;
if (total > 0) {
FlutterNewBadger.setBadge(total);
} else {
FlutterNewBadger.removeBadge();
}
} catch (e) {
debugPrint('BadgeManager._syncNativeDebounced error: $e');
}
_syncTimer = null;
});
}
// safe wrapper: 给单个 future 加超时与兜底返回
Future<T> _safe<T>(Future<T> future, T fallback, {Duration timeout = const Duration(seconds: 5)}) async {
try {
return await future.timeout(timeout);
} catch (e, st) {
// 报错不抛出到外层,记录并返回 fallback
debugPrint('BadgeManager._safe error: $e\n$st');
return fallback;
}
}
/// 初始化所有模块(并行发起,但每个接口独立 timeout & 提交结果)
Future<void> initAllModules() async {
// 不 await 整个 Future.wait使调用方不会因为单个慢接口阻塞
try {
// 每个请求都通过 _safe 包裹,设置超时与兜底
final fWork = _safe<Map<String, dynamic>>(
ApiService.getWork().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 6),
);
final fNotif = _safe<Map<String, dynamic>>(
ApiService.getNotifRedPoint().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 4),
);
final fCheck = _safe<Map<String, dynamic>>(
ApiService.getSafetyEnvironmentalInspectionCount().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 5),
);
final fRed = _safe<Map<String, dynamic>>(
ApiService.getRedPoint().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 5),
);
// 按接口独立处理完成即更新并合并通知progressive update
fWork.then((workJson) {
try {
final hid = (workJson['hidCount'] as Map<String, dynamic>?) ?? {};
_appDysCount = (hid['dys'] ?? 0) as int? ?? 0;
_appDzgCount = (hid['dzg'] ?? 0) as int? ?? 0;
_appCount = _appDysCount + _appDzgCount;
} catch (e, st) {
debugPrint('BadgeManager.parse workJson error: $e\n$st');
}
_scheduleNotify();
_syncNativeDebounced();
});
fNotif.then((notifJson) {
try {
_notifCount = (notifJson['count'] as int?) ?? 0;
} catch (e, st) {
debugPrint('BadgeManager.parse notifJson error: $e\n$st');
}
_scheduleNotify();
_syncNativeDebounced();
});
fCheck.then((checkJson) {
try {
// 兼容不同返回结构,防止空指针
int checkedCount = 0, repulseAndCheckCount = 0, confirmCount = 0, repulseCount = 0;
if (checkJson['checkedCount'] is Map) checkedCount = (checkJson['checkedCount']['checkedCount'] ?? 0) as int? ?? 0;
if (checkJson['repulseAndCheckCount'] is Map) repulseAndCheckCount = (checkJson['repulseAndCheckCount']['repulseAndCheckCount'] ?? 0) as int? ?? 0;
if (checkJson['confirmCount'] is Map) confirmCount = (checkJson['confirmCount']['confirmCount'] ?? 0) as int? ?? 0;
if (checkJson['repulseCount'] is Map) repulseCount = (checkJson['repulseCount']['repulseCount'] ?? 0) as int? ?? 0;
_envInspectCount = checkedCount + repulseAndCheckCount + confirmCount + repulseCount;
} catch (e, st) {
debugPrint('BadgeManager.parse checkJson error: $e\n$st');
}
_scheduleNotify();
_syncNativeDebounced();
});
fRed.then((redPointJson) {
try {
_eightWorkCount = 0;
final m = (redPointJson['count'] as Map<String, dynamic>?) ?? {};
for (final v in m.values) {
_eightWorkCount += (v ?? 0) as int? ?? 0;
}
} catch (e, st) {
debugPrint('BadgeManager.parse redPointJson error: $e\n$st');
}
_scheduleNotify();
_syncNativeDebounced();
});
// 可选:等待所有结束(不阻塞调用方),用于 debug 或需要最终一致性的场景
unawaited(Future.wait([fWork, fNotif, fCheck, fRed]).then((_) {
debugPrint('BadgeManager.initAllModules: all done at ${DateTime.now()}');
}));
} catch (e, st) {
debugPrint('BadgeManager.initAllModules unexpected error: $e\n$st');
}
}
// 下面的 updateX 方法也做了超时保护并使用 _onModuleChanged 合并通知
void updateAppCount() async {
try {
final workJson = await _safe<Map<String, dynamic>>(
ApiService.getWork().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 5),
);
final hid = (workJson['hidCount'] as Map<String, dynamic>?) ?? {};
_appDysCount = (hid['dys'] ?? 0) as int? ?? 0;
_appDzgCount = (hid['dzg'] ?? 0) as int? ?? 0;
_appCount = _appDysCount + _appDzgCount;
_onModuleChanged();
} catch (e) {
debugPrint('updateAppCount error: $e');
}
}
void updateNotifCount() async {
try {
final notifJson = await _safe<Map<String, dynamic>>(
ApiService.getNotifRedPoint().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 4),
);
_notifCount = (notifJson['count'] as int?) ?? 0;
_onModuleChanged();
} catch (e) {
debugPrint('updateNotifCount error: $e');
}
}
void updateEnvInspectCount() async {
try {
final checkJson = await _safe<Map<String, dynamic>>(
ApiService.getSafetyEnvironmentalInspectionCount().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 5),
);
int checkedCount = 0, repulseAndCheckCount = 0, confirmCount = 0, repulseCount = 0;
if (checkJson['checkedCount'] is Map) checkedCount = (checkJson['checkedCount']['checkedCount'] ?? 0) as int? ?? 0;
if (checkJson['repulseAndCheckCount'] is Map) repulseAndCheckCount = (checkJson['repulseAndCheckCount']['repulseAndCheckCount'] ?? 0) as int? ?? 0;
if (checkJson['confirmCount'] is Map) confirmCount = (checkJson['confirmCount']['confirmCount'] ?? 0) as int? ?? 0;
if (checkJson['repulseCount'] is Map) repulseCount = (checkJson['repulseCount']['repulseCount'] ?? 0) as int? ?? 0;
_envInspectCount = checkedCount + repulseAndCheckCount + confirmCount + repulseCount;
_onModuleChanged();
} catch (e) {
debugPrint('updateEnvInspectCount error: $e');
}
}
void updateEightWorkCount() async {
try {
final redPointJson = await _safe<Map<String, dynamic>>(
ApiService.getRedPoint().then((r) => r as Map<String, dynamic>),
<String, dynamic>{},
timeout: const Duration(seconds: 5),
);
int sum = 0;
final m = (redPointJson['count'] as Map<String, dynamic>?) ?? {};
for (final v in m.values) sum += (v ?? 0) as int? ?? 0;
_eightWorkCount = sum;
_onModuleChanged();
} catch (e) {
debugPrint('updateEightWorkCount error: $e');
}
}
void clearAll() {
_appCount = _notifCount = _envInspectCount = _eightWorkCount = 0;
_appDysCount = _appDzgCount = 0;
_syncNativeDebounced();
_scheduleNotify();
}
void _onModuleChanged() {
_syncNativeDebounced();
_scheduleNotify();
}
}