Skip to content

Commit fc79092

Browse files
committed
2 parents 23c9149 + 64a8b6f commit fc79092

11 files changed

+670
-45
lines changed

lib/pages/analytics_page.dart

Lines changed: 365 additions & 13 deletions
Large diffs are not rendered by default.

lib/pages/annual_report_display_page.dart

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class AnnualReportDisplayPage extends StatefulWidget {
1919
final VoidCallback? onClose;
2020
final bool autoStart;
2121
final Future<bool> Function()? onBeforeGenerate;
22+
final Set<String> excludedUsernames;
2223

2324
const AnnualReportDisplayPage({
2425
super.key,
@@ -28,6 +29,7 @@ class AnnualReportDisplayPage extends StatefulWidget {
2829
this.onClose,
2930
this.autoStart = true,
3031
this.onBeforeGenerate,
32+
this.excludedUsernames = const {},
3133
});
3234

3335
@override
@@ -55,6 +57,9 @@ class _AnnualReportDisplayPageState extends State<AnnualReportDisplayPage> {
5557
int _totalProgress = 0;
5658
int? _dbModifiedTime;
5759

60+
Set<String> get _normalizedExcludedUsernames =>
61+
widget.excludedUsernames.map((e) => e.trim().toLowerCase()).toSet();
62+
5863
@override
5964
void initState() {
6065
super.initState();
@@ -79,6 +84,9 @@ class _AnnualReportDisplayPageState extends State<AnnualReportDisplayPage> {
7984
// 每次初始化时都重新创建后台服务,确保使用最新的数据库路径
8085
if (dbPath != null) {
8186
_backgroundService = AnalyticsBackgroundService(dbPath);
87+
if (_normalizedExcludedUsernames.isNotEmpty) {
88+
_backgroundService!.setExcludedUsernames(_normalizedExcludedUsernames);
89+
}
8290
} else {}
8391

8492
// 获取数据库修改时间
@@ -105,6 +113,16 @@ class _AnnualReportDisplayPageState extends State<AnnualReportDisplayPage> {
105113
final cachedData = await AnnualReportCacheService.loadReport(widget.year);
106114
if (cachedData != null) {
107115
await logger.info('AnnualReportPage', '找到缓存数据,检查时间戳');
116+
final cachedExcluded =
117+
(cachedData['excludedUsernames'] as List?)
118+
?.map((e) => e.toString())
119+
.toList() ??
120+
<String>[];
121+
final cachedExcludedSet =
122+
cachedExcluded.map((e) => e.trim().toLowerCase()).toSet();
123+
final excludedChanged =
124+
cachedExcludedSet.length != _normalizedExcludedUsernames.length ||
125+
!cachedExcludedSet.containsAll(_normalizedExcludedUsernames);
108126
// 检查数据库是否有更新
109127
final cachedDbTime = cachedData['dbModifiedTime'] as int?;
110128
await logger.info(
@@ -114,9 +132,12 @@ class _AnnualReportDisplayPageState extends State<AnnualReportDisplayPage> {
114132
final dbChanged =
115133
cachedDbTime == null || cachedDbTime < _dbModifiedTime!;
116134

117-
if (dbChanged) {
135+
if (dbChanged || excludedChanged) {
118136
// 数据库已更新,询问用户
119-
await logger.info('AnnualReportPage', '数据库已更新,显示确认对话框');
137+
await logger.info(
138+
'AnnualReportPage',
139+
'缓存已过期,显示确认对话框',
140+
);
120141
if (!mounted) return;
121142
final shouldRegenerate = await _showDatabaseChangedDialog();
122143

@@ -240,6 +261,8 @@ class _AnnualReportDisplayPageState extends State<AnnualReportDisplayPage> {
240261

241262
// 保存数据库修改时间
242263
data['dbModifiedTime'] = _dbModifiedTime;
264+
data['excludedUsernames'] =
265+
_normalizedExcludedUsernames.toList()..sort();
243266
await logger.debug('AnnualReportPage', '保存数据库修改时间: $_dbModifiedTime');
244267

245268
// 保存到缓存

lib/pages/friend_selection_page.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,21 @@ class _FriendSelectionPageState extends State<FriendSelectionPage> {
3030
void initState() {
3131
super.initState();
3232
_analyticsService = AdvancedAnalyticsService(widget.databaseService);
33-
_loadFriendList();
33+
WidgetsBinding.instance.addPostFrameCallback((_) async {
34+
final appState = context.read<AppState>();
35+
final excluded =
36+
await appState.configService.getAnalyticsExcludedUsernames();
37+
final normalized = excluded.map((e) => e.toLowerCase()).toSet();
38+
normalized.add('filehelper');
39+
final myWxid =
40+
widget.databaseService.currentAccountWxid ??
41+
await appState.configService.getManualWxid();
42+
if (myWxid != null && myWxid.isNotEmpty) {
43+
normalized.add(myWxid.toLowerCase());
44+
}
45+
_analyticsService.setExcludedUsernames(normalized);
46+
_loadFriendList();
47+
});
3448
}
3549

3650
/// 加载好友列表(按聊天数量排序)

lib/services/advanced_analytics_service.dart

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ import 'analytics_service.dart';
3333
class AdvancedAnalyticsService {
3434
final DatabaseService _databaseService;
3535
final AnalyticsService _analyticsService;
36+
Set<String> _excludedUsernames = {};
3637

3738
int? _filterYear; // 年份过滤器,null表示显示全部年份
3839

3940
// 系统账号和无效账号的黑名单,避免分析时包含无关数据
4041
static const _systemAccounts = {
41-
'filehelper',
4242
'fmessage',
4343
'medianote',
4444
'newsapp',
@@ -55,6 +55,11 @@ class AdvancedAnalyticsService {
5555
AdvancedAnalyticsService(this._databaseService)
5656
: _analyticsService = AnalyticsService(_databaseService);
5757

58+
void setExcludedUsernames(Set<String> usernames) {
59+
_excludedUsernames =
60+
usernames.map((name) => name.trim().toLowerCase()).toSet();
61+
}
62+
5863
/// 设置年份过滤器,用于限定分析的数据范围
5964
void setYearFilter(int? year) {
6065
_filterYear = year;
@@ -95,11 +100,17 @@ class AdvancedAnalyticsService {
95100
return false;
96101
}
97102

103+
bool _isCustomExcluded(String username) {
104+
if (username.isEmpty) return false;
105+
return _excludedUsernames.contains(username.toLowerCase());
106+
}
107+
98108
/// 分析作息规律(24小时×7天热力图)
99109
Future<ActivityHeatmap> analyzeActivityPattern() async {
100110
// 使用SQL直接统计,避免加载所有消息到内存
101111
final data = await _databaseService.getActivityHeatmapData(
102112
year: _filterYear,
113+
excludedUsernames: _excludedUsernames,
103114
);
104115

105116
// 计算最大值
@@ -121,7 +132,12 @@ class AdvancedAnalyticsService {
121132
final myWxid = _databaseService.currentAccountWxid;
122133
final normalizedMyWxid = myWxid?.toLowerCase();
123134
final privateSessions = sessions
124-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
135+
.where(
136+
(s) =>
137+
!s.isGroup &&
138+
!_isSystemAccount(s.username) &&
139+
!_isCustomExcluded(s.username),
140+
)
125141
.where((s) {
126142
final username = s.username.toLowerCase();
127143
if (username == 'filehelper') return false;
@@ -346,7 +362,12 @@ class AdvancedAnalyticsService {
346362
final myWxid = _databaseService.currentAccountWxid;
347363
final normalizedMyWxid = myWxid?.toLowerCase();
348364
final privateSessions = sessions
349-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
365+
.where(
366+
(s) =>
367+
!s.isGroup &&
368+
!_isSystemAccount(s.username) &&
369+
!_isCustomExcluded(s.username),
370+
)
350371
.where((s) {
351372
final username = s.username.toLowerCase();
352373
if (username == 'filehelper') return false;
@@ -407,7 +428,12 @@ class AdvancedAnalyticsService {
407428
final myWxid = _databaseService.currentAccountWxid;
408429
final normalizedMyWxid = myWxid?.toLowerCase();
409430
final privateSessions = sessions
410-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
431+
.where(
432+
(s) =>
433+
!s.isGroup &&
434+
!_isSystemAccount(s.username) &&
435+
!_isCustomExcluded(s.username),
436+
)
411437
.where((s) {
412438
final username = s.username.toLowerCase();
413439
if (username == 'filehelper') return false;
@@ -556,7 +582,12 @@ class AdvancedAnalyticsService {
556582
final myWxid = _databaseService.currentAccountWxid;
557583
final normalizedMyWxid = myWxid?.toLowerCase();
558584
final privateSessions = sessions
559-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
585+
.where(
586+
(s) =>
587+
!s.isGroup &&
588+
!_isSystemAccount(s.username) &&
589+
!_isCustomExcluded(s.username),
590+
)
560591
.where((s) {
561592
final username = s.username.toLowerCase();
562593
if (username == 'filehelper') return false;
@@ -625,7 +656,12 @@ class AdvancedAnalyticsService {
625656
final myWxid = _databaseService.currentAccountWxid;
626657
final normalizedMyWxid = myWxid?.toLowerCase();
627658
final privateSessions = sessions
628-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
659+
.where(
660+
(s) =>
661+
!s.isGroup &&
662+
!_isSystemAccount(s.username) &&
663+
!_isCustomExcluded(s.username),
664+
)
629665
.where((s) {
630666
final username = s.username.toLowerCase();
631667
if (username == 'filehelper') return false;
@@ -702,7 +738,12 @@ class AdvancedAnalyticsService {
702738
final myWxid = _databaseService.currentAccountWxid;
703739
final normalizedMyWxid = myWxid?.toLowerCase();
704740
final privateSessions = sessions
705-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
741+
.where(
742+
(s) =>
743+
!s.isGroup &&
744+
!_isSystemAccount(s.username) &&
745+
!_isCustomExcluded(s.username),
746+
)
706747
.where((s) {
707748
final username = s.username.toLowerCase();
708749
if (username == 'filehelper') return false;
@@ -778,7 +819,12 @@ class AdvancedAnalyticsService {
778819
final myWxid = _databaseService.currentAccountWxid;
779820
final normalizedMyWxid = myWxid?.toLowerCase();
780821
final privateSessions = sessions
781-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
822+
.where(
823+
(s) =>
824+
!s.isGroup &&
825+
!_isSystemAccount(s.username) &&
826+
!_isCustomExcluded(s.username),
827+
)
782828
.where((s) {
783829
final username = s.username.toLowerCase();
784830
if (username == 'filehelper') return false;
@@ -869,7 +915,12 @@ class AdvancedAnalyticsService {
869915
Future<List<FriendshipRanking>> getMutualFriendsRanking(int limit) async {
870916
final sessions = await _databaseService.getSessions();
871917
final privateSessions = sessions
872-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
918+
.where(
919+
(s) =>
920+
!s.isGroup &&
921+
!_isSystemAccount(s.username) &&
922+
!_isCustomExcluded(s.username),
923+
)
873924
.toList();
874925

875926
final balanceList = <Map<String, dynamic>>[];
@@ -941,7 +992,12 @@ class AdvancedAnalyticsService {
941992
final myWxid = _databaseService.currentAccountWxid;
942993
final normalizedMyWxid = myWxid?.toLowerCase();
943994
final privateSessions = sessions
944-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
995+
.where(
996+
(s) =>
997+
!s.isGroup &&
998+
!_isSystemAccount(s.username) &&
999+
!_isCustomExcluded(s.username),
1000+
)
9451001
.where((s) {
9461002
final username = s.username.toLowerCase();
9471003
if (username == 'filehelper') return false;
@@ -1027,7 +1083,12 @@ class AdvancedAnalyticsService {
10271083
final myWxid = _databaseService.currentAccountWxid;
10281084
final normalizedMyWxid = myWxid?.toLowerCase();
10291085
final privateSessions = sessions
1030-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
1086+
.where(
1087+
(s) =>
1088+
!s.isGroup &&
1089+
!_isSystemAccount(s.username) &&
1090+
!_isCustomExcluded(s.username),
1091+
)
10311092
.where((s) {
10321093
final username = s.username.toLowerCase();
10331094
if (username == 'filehelper') return false;
@@ -1130,7 +1191,12 @@ class AdvancedAnalyticsService {
11301191
final myWxid = _databaseService.currentAccountWxid;
11311192
final normalizedMyWxid = myWxid?.toLowerCase();
11321193
final privateSessions = sessions
1133-
.where((s) => !s.isGroup && !_isSystemAccount(s.username))
1194+
.where(
1195+
(s) =>
1196+
!s.isGroup &&
1197+
!_isSystemAccount(s.username) &&
1198+
!_isCustomExcluded(s.username),
1199+
)
11341200
.where((s) {
11351201
final username = s.username.toLowerCase();
11361202
if (username == 'filehelper') return false;
@@ -1150,7 +1216,10 @@ class AdvancedAnalyticsService {
11501216

11511217
// 批量获取所有会话的消息日期
11521218
final allSessionsDates = await _databaseService
1153-
.getAllPrivateSessionsMessageDates(filterYear: _filterYear);
1219+
.getAllPrivateSessionsMessageDates(
1220+
filterYear: _filterYear,
1221+
excludedUsernames: _excludedUsernames,
1222+
);
11541223

11551224
int globalMaxStreak = 0;
11561225
String? bestFriendUsername;
@@ -1221,6 +1290,7 @@ class AdvancedAnalyticsService {
12211290
Future<List<MessageTypeStats>> analyzeMessageTypeDistribution() async {
12221291
final typeCount = await _databaseService.getAllMessageTypeDistribution(
12231292
filterYear: _filterYear,
1293+
excludedUsernames: _excludedUsernames,
12241294
);
12251295

12261296
if (typeCount.isEmpty) return [];
@@ -1289,6 +1359,7 @@ class AdvancedAnalyticsService {
12891359
Future<MessageLengthData> analyzeMessageLength() async {
12901360
final stats = await _databaseService.getTextMessageLengthStats(
12911361
year: _filterYear,
1362+
excludedUsernames: _excludedUsernames,
12921363
);
12931364

12941365
final averageLength = stats['averageLength'] as double;

0 commit comments

Comments
 (0)