Skip to content

Commit 15ecdc5

Browse files
committed
FEAT: 增加网页词典广告过滤开关
1 parent e26b283 commit 15ecdc5

15 files changed

Lines changed: 370 additions & 15 deletions

‎TASKS.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
55
## 本次完成
66

7+
- [x] 移除词典广告过滤说明(2026-10-10):删除设置页说明及中英文文案;本地化生成、diff 检查通过,未运行测试。完成时间 22:37
8+
- [x] 扩展网页词典广告过滤规则(2026-10-10):新增国际与中国广告域名、第三方广告路径和 CSS 隐藏规则;格式化、diff 检查通过,未运行测试。**完成时间**: 2026-10-10 22:17
79
- [x] 网页词典新增欧路词典(2026-10-10):新增可配置网页源 `eudic`,使用欧路英汉词条页 URL,支持词组空格编码;来源自动出现在词典切换器与设置列表,默认可见且可禁用,默认源仍为本地词典。新增 URL、注册表可见性及禁用行为回归测试。两个定向测试文件共 58 项通过,3 个 Dart 文件定向分析通过,`git diff --check` 通过。未运行 `scripts/check.sh`:改动限于网页词典配置与来源可见性,定向检查覆盖相关行为。未运行 Maestro:沙箱内 ADB 守护进程启动失败(`Operation not permitted`),现有首启 smoke flow 会清空应用数据;未在设备验证 WebView 实际加载。**完成时间**: 2026-10-10 19:05
810
- [x] 限制共享后台文件下载进度更新频率(2026-10-10):百度网盘和播客共用的 `BackgroundFileDownloadService` 按任务将应用层进度回调限制为最多每 100ms 一次;初始进度、已知总量下的完成进度,以及任务终态的最终字节数仍会及时发布,失败/异常路径会冲刷最后待发布进度。新增 1000 次突发进度回调回归测试,确认通知被合并且最终字节数保留;完整下载服务测试 10 项通过,改动的 2 个 Dart 文件定向分析通过,`git diff --check` 通过。未运行 `scripts/check.sh`:改动仅限共享下载进度通知,定向测试覆盖修改范围;尚未做真机下载速度前后对比。**完成时间**: 2026-10-10 09:54
911
- [x] 定位并压制 ASR 下载进度回调造成的吞吐下降(2026-10-10):日志中的 App 是 sidecar 优化后重新构建的版本;同 URL 的 Dart/Dio 流式写盘复测为 2.01 秒、约 31.0 MB/s,收到 11,414 个数据块;App 日志为 62,337,248 字节、14.110 秒、约 4.42 MB/s。根因是每个数据块都触发 ASR provider 状态更新,而设置页订阅整个状态;限频前的 10,000 次回调回归用例产生了 10,000 次状态更新。现将 UI 进度状态更新限制为每 100ms 至多一次,100% 仍立即发布。Dio 同 URL 无重定向且无内容编码,直连 curl 复测约 24.9 MB/s。Provider 与设置页定向测试 15 项通过,2 个 Dart 文件定向分析通过,`git diff --check` 通过。未运行 `scripts/check.sh`:改动限于 ASR 进度通知频率,定向测试覆盖相关状态流。**完成时间**: 2026-10-10 09:16

‎lib/l10n/app_en.arb‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,6 +2595,7 @@
25952595
"dictionarySources": "Dictionary Sources",
25962596
"dictionarySourcesDescription": "Disabled dictionaries won't appear in the lookup switcher",
25972597
"dictionaryAutoSpeakOnLookup": "Auto-play Pronunciation",
2598+
"dictionaryAdFilterTitle": "Block ads in web dictionaries",
25982599
"dictSourceLocal": "Local Dictionary",
25992600
"dictSourceAi": "AI Dictionary",
26002601
"dictSourceCambridge": "Cambridge",

‎lib/l10n/app_localizations.dart‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9152,6 +9152,12 @@ abstract class AppLocalizations {
91529152
/// **'Auto-play Pronunciation'**
91539153
String get dictionaryAutoSpeakOnLookup;
91549154

9155+
/// No description provided for @dictionaryAdFilterTitle.
9156+
///
9157+
/// In en, this message translates to:
9158+
/// **'Block ads in web dictionaries'**
9159+
String get dictionaryAdFilterTitle;
9160+
91559161
/// No description provided for @dictSourceLocal.
91569162
///
91579163
/// In en, this message translates to:

‎lib/l10n/app_localizations_en.dart‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5225,6 +5225,9 @@ class AppLocalizationsEn extends AppLocalizations {
52255225
@override
52265226
String get dictionaryAutoSpeakOnLookup => 'Auto-play Pronunciation';
52275227

5228+
@override
5229+
String get dictionaryAdFilterTitle => 'Block ads in web dictionaries';
5230+
52285231
@override
52295232
String get dictSourceLocal => 'Local Dictionary';
52305233

‎lib/l10n/app_localizations_zh.dart‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4984,6 +4984,9 @@ class AppLocalizationsZh extends AppLocalizations {
49844984
@override
49854985
String get dictionaryAutoSpeakOnLookup => '查词时自动播放发音';
49864986

4987+
@override
4988+
String get dictionaryAdFilterTitle => '屏蔽网页词典广告';
4989+
49874990
@override
49884991
String get dictSourceLocal => '本地词典';
49894992

‎lib/l10n/app_zh.arb‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,6 +2109,7 @@
21092109
"dictionarySources": "词典源",
21102110
"dictionarySourcesDescription": "关闭的词典不会出现在查词切换器中",
21112111
"dictionaryAutoSpeakOnLookup": "查词时自动播放发音",
2112+
"dictionaryAdFilterTitle": "屏蔽网页词典广告",
21122113
"dictSourceLocal": "本地词典",
21132114
"dictSourceAi": "AI 词典",
21142115
"dictSourceCambridge": "Cambridge",

‎lib/models/dictionary/dictionary_settings.dart‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,44 @@ class DictionarySettings {
2121
/// 查词面板打开或切换到新词时是否自动播放发音
2222
final bool autoSpeakOnLookup;
2323

24+
/// 是否在网页词典中启用通用广告过滤
25+
final bool adFilteringEnabled;
26+
2427
/// 默认源 id 缺省值
2528
static const defaultId = 'local';
2629

2730
DictionarySettings({
2831
this.defaultSourceId = defaultId,
2932
Set<String> disabledIds = const {},
3033
this.autoSpeakOnLookup = true,
34+
this.adFilteringEnabled = false,
3135
}) : disabledIds = UnmodifiableSetView(Set.of(disabledIds));
3236

3337
DictionarySettings copyWith({
3438
String? defaultSourceId,
3539
Set<String>? disabledIds,
3640
bool? autoSpeakOnLookup,
41+
bool? adFilteringEnabled,
3742
}) => DictionarySettings(
3843
defaultSourceId: defaultSourceId ?? this.defaultSourceId,
3944
disabledIds: disabledIds ?? this.disabledIds,
4045
autoSpeakOnLookup: autoSpeakOnLookup ?? this.autoSpeakOnLookup,
46+
adFilteringEnabled: adFilteringEnabled ?? this.adFilteringEnabled,
4147
);
4248

4349
Map<String, dynamic> toJson() => {
4450
'defaultSourceId': defaultSourceId,
4551
'disabledIds': disabledIds.toList(),
4652
'autoSpeakOnLookup': autoSpeakOnLookup,
53+
'adFilteringEnabled': adFilteringEnabled,
4754
};
4855

4956
/// 防御性解析:字段缺失/类型不符回退缺省
5057
factory DictionarySettings.fromJson(Map<String, dynamic> json) {
5158
final rawDefault = json['defaultSourceId'];
5259
final rawDisabled = json['disabledIds'];
5360
final rawAutoSpeak = json['autoSpeakOnLookup'];
61+
final rawAdFilteringEnabled = json['adFilteringEnabled'];
5462
return DictionarySettings(
5563
defaultSourceId: rawDefault is String && rawDefault.isNotEmpty
5664
? rawDefault
@@ -59,6 +67,9 @@ class DictionarySettings {
5967
? rawDisabled.whereType<String>().toSet()
6068
: const {},
6169
autoSpeakOnLookup: rawAutoSpeak is bool ? rawAutoSpeak : true,
70+
adFilteringEnabled: rawAdFilteringEnabled is bool
71+
? rawAdFilteringEnabled
72+
: false,
6273
);
6374
}
6475

@@ -69,13 +80,15 @@ class DictionarySettings {
6980
runtimeType == other.runtimeType &&
7081
defaultSourceId == other.defaultSourceId &&
7182
_setEquals(disabledIds, other.disabledIds) &&
72-
autoSpeakOnLookup == other.autoSpeakOnLookup;
83+
autoSpeakOnLookup == other.autoSpeakOnLookup &&
84+
adFilteringEnabled == other.adFilteringEnabled;
7385

7486
@override
7587
int get hashCode => Object.hash(
7688
defaultSourceId,
7789
Object.hashAllUnordered(disabledIds),
7890
autoSpeakOnLookup,
91+
adFilteringEnabled,
7992
);
8093

8194
static bool _setEquals(Set<String> a, Set<String> b) =>

‎lib/providers/dictionary/dictionary_settings_provider.dart‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ class DictionarySettingsNotifier extends _$DictionarySettingsNotifier {
5454
await _persist(state.copyWith(autoSpeakOnLookup: enabled));
5555
}
5656

57+
/// 设置网页词典广告过滤开关。
58+
Future<void> setAdFilteringEnabled(bool enabled) async {
59+
if (state.adFilteringEnabled == enabled) return;
60+
await _persist(state.copyWith(adFilteringEnabled: enabled));
61+
}
62+
5763
/// 启用/禁用某词典源
5864
///
5965
/// 禁用前校验该源 `canBeDisabled`;禁用当前默认源时默认自动回退。

‎lib/screens/dictionary_settings_screen.dart‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,21 @@ class DictionarySettingsScreen extends ConsumerWidget {
3737
),
3838
children: [
3939
Card(
40-
child: SwitchListTile(
41-
secondary: const Icon(Icons.volume_up_outlined),
42-
title: Text(l10n.dictionaryAutoSpeakOnLookup),
43-
value: settings.autoSpeakOnLookup,
44-
onChanged: notifier.setAutoSpeakOnLookup,
40+
child: Column(
41+
children: [
42+
SwitchListTile(
43+
secondary: const Icon(Icons.volume_up_outlined),
44+
title: Text(l10n.dictionaryAutoSpeakOnLookup),
45+
value: settings.autoSpeakOnLookup,
46+
onChanged: notifier.setAutoSpeakOnLookup,
47+
),
48+
SwitchListTile(
49+
secondary: const Icon(Icons.block_outlined),
50+
title: Text(l10n.dictionaryAdFilterTitle),
51+
value: settings.adFilteringEnabled,
52+
onChanged: notifier.setAdFilteringEnabled,
53+
),
54+
],
4555
),
4656
),
4757
const SizedBox(height: AppSpacing.m),

0 commit comments

Comments
 (0)