Skip to content

Commit 11b56c4

Browse files
committed
FEAT: 精听首次点「听不太懂」弹窗说明自动收藏,弹窗内可直接开关
- 新增持久化标记 unclearReminderShown(仅本机),首次点击先弹窗,确认后进入讲解 - 弹窗内开关即时写回「听不懂时自动收藏」设置,并提示可在学习设置中修改 - 修正上一提交的英文文案为 Unclear / saved 用语 - 命名统一:收藏用 save,「听不太懂」用 unclear(持久化字符串值保持不变) - 补充 provider、弹窗、精听页测试;修复测试 fake 未实现新方法导致的编译失败
1 parent 86b04fc commit 11b56c4

21 files changed

Lines changed: 475 additions & 107 deletions

‎TASKS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
> 当前待办与本次完成记录;此前完成任务已归档,详见 [2026-10-29 归档](./docs/tasks-archive/tasks-2026-10-29-completed.md)、[2026-09-29 归档](./docs/tasks-archive/tasks-2026-09-29-completed.md)。
44
55
## 本次完成
6+
- [x] 首次点「听不太懂」弹出自动收藏说明(一次性):精听中第一次点击「听不太懂」,进入讲解页前弹窗说明该操作会自动收藏句子,弹窗内可直接切换「听不懂时自动收藏」开关(即时生效),并提示可在「学习设置」随时修改。已提示标记 `learning_cant_understand_auto_favorite_reminder_shown` 存 SP(仅本机,老用户升级后也会提示一次)。弹窗不可点外部关闭,保证标记必定落库。同时修正上一条英文文案为 Unclear / saved 用语。新增测试:provider 标记与幂等、弹窗开关写回与关闭路径、精听页首次弹窗后进入讲解、弹窗内关开关后进入讲解。精听页、学习设置 provider 与弹窗相关测试通过,改动文件 `flutter analyze` 无问题。**完成时间**: 2026-10-29
67
- [x] 修复精听切换收藏时抛出 `Failed to interpolate TextStyles with different inherit values`:未收藏句子点「听不太懂」旁收藏后,`PracticeNormalModeView` 的 Row 子项按位置复用 `FilledButton` element,「听不太懂」的文字样式被插值到「取消标记」按钮。修复:两个按钮加稳定 `ValueKey`。新增回归测试(修复前复现插值异常,修复后通过);相关 practice / 精听 / 复习页测试 205 项通过,改动文件 `flutter analyze` 无问题。**完成时间**: 2026-10-29
78
- [x] 学习设置新增「听不懂时自动收藏」开关(偏好 `learning_auto_favorite_on_cant_understand`,默认开启,保持原行为):关闭后精听点击「听不太懂」只进入讲解,不再把当前句加入收藏(不改动已收藏句);走 `LearningSettings` 与云同步白名单。新增测试:provider setter 与启动读取、精听进入讲解页开启/关闭两条路径;`learning_settings_screen_test` 的两个引导用例因新增卡片把引导区挤出默认视口,改为加高测试视口后再点击(基线 14 项通过,改后仍 14 项通过)。相关测试 provider/精听/同步/设置页合计通过,改动文件 `flutter analyze` 无问题。**完成时间**: 2026-10-29
89
- [x] 学习页「为你推荐」卡片可关闭,并新增设置入口「显示设置」:推荐卡标题行右侧加关闭按钮,点击弹确认框,确认后隐藏(偏好 `learning_show_study_recommendation`,默认开启,走 `LearningSettings` 与云同步白名单);设置页「学习」分组新增「显示设置」页,可重新开启推荐卡片。新增测试:provider setter 与启动读取、同步白名单、学习页取消/确认/设置关闭三条路径、显示设置页开关。相关测试 119 项通过,改动文件 `flutter analyze` 无问题。**完成时间**: 2026-10-29

‎lib/features/user_preferences/data/local_user_preferences_store.dart‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class LocalUserPreferencesStore {
3535
LearningSettingsKeys.listenAndRepeatRatingEnabled: true,
3636
LearningSettingsKeys.retellRatingEnabled: true,
3737
LearningSettingsKeys.showStudyRecommendation: true,
38-
LearningSettingsKeys.autoFavoriteOnCantUnderstand: true,
38+
LearningSettingsKeys.autoSaveOnUnclear: true,
3939
};
4040

4141
UserPreferencesDocument capture() {
@@ -193,8 +193,7 @@ class LocalUserPreferencesStore {
193193
'listenAndRepeatRatingEnabled',
194194
LearningSettingsKeys.retellRatingEnabled: 'retellRatingEnabled',
195195
LearningSettingsKeys.showStudyRecommendation: 'showStudyRecommendation',
196-
LearningSettingsKeys.autoFavoriteOnCantUnderstand:
197-
'autoFavoriteOnCantUnderstand',
196+
LearningSettingsKeys.autoSaveOnUnclear: 'autoFavoriteOnCantUnderstand',
198197
};
199198

200199
static String _learningFieldName(String storageKey) =>

‎lib/l10n/app_en.arb‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@
748748
},
749749
"intensiveListenPeek": "Peek at subtitles",
750750
"intensiveListenHideSubtitle": "Hide subtitles",
751-
"intensiveListenCantUnderstand": "Unclear",
751+
"intensiveListenUnclear": "Unclear",
752752
"intensiveListenAutoMarkedDifficult": "Auto-save, tap to undo",
753753
"intensiveListenMarkedDifficult": "Unsave",
754754
"intensiveListenNotDifficult": "Save",
@@ -2292,8 +2292,14 @@
22922292
"listenAndRepeatRatingSubtitle": "When off, recordings are kept but recognition and scoring are skipped",
22932293
"retellRatingToggle": "Show rating after each retelling",
22942294
"retellRatingSubtitle": "When off, your recording can still be played back, but scores aren't shown",
2295-
"autoFavoriteOnCantUnderstandToggle": "Auto-favorite when marked as hard to understand",
2296-
"autoFavoriteOnCantUnderstandSubtitle": "When on, tapping \"Hard to understand\" in intensive listening adds the sentence to favorites",
2295+
"autoSaveOnUnclearToggle": "Auto-save when marked Unclear",
2296+
"autoSaveOnUnclearSubtitle": "When on, tapping \"Unclear\" in intensive listening saves the sentence",
2297+
"unclearAutoSaveDialogTitle": "Auto-save unclear sentences",
2298+
"unclearAutoSaveDialogMessage": "When you tap \"Unclear\", the sentence is saved automatically so you can review it later.",
2299+
"unclearAutoSaveSwitchOn": "On",
2300+
"unclearAutoSaveSwitchOff": "Off",
2301+
"unclearAutoSaveDialogHint": "You can change this anytime in Me → Learning Settings.",
2302+
"unclearAutoSaveDialogConfirm": "Got it",
22972303
"retellSkip": "Skip",
22982304
"retellSkippedSuffix": "Skipped",
22992305
"skipSilenceTitle": "Auto-skip Silence",

‎lib/l10n/app_localizations.dart‎

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,11 +2450,11 @@ abstract class AppLocalizations {
24502450
/// **'Hide subtitles'**
24512451
String get intensiveListenHideSubtitle;
24522452

2453-
/// No description provided for @intensiveListenCantUnderstand.
2453+
/// No description provided for @intensiveListenUnclear.
24542454
///
24552455
/// In en, this message translates to:
24562456
/// **'Unclear'**
2457-
String get intensiveListenCantUnderstand;
2457+
String get intensiveListenUnclear;
24582458

24592459
/// No description provided for @intensiveListenAutoMarkedDifficult.
24602460
///
@@ -7748,17 +7748,53 @@ abstract class AppLocalizations {
77487748
/// **'When off, your recording can still be played back, but scores aren\'t shown'**
77497749
String get retellRatingSubtitle;
77507750

7751-
/// No description provided for @autoFavoriteOnCantUnderstandToggle.
7751+
/// No description provided for @autoSaveOnUnclearToggle.
77527752
///
77537753
/// In en, this message translates to:
7754-
/// **'Auto-favorite when marked as hard to understand'**
7755-
String get autoFavoriteOnCantUnderstandToggle;
7754+
/// **'Auto-save when marked Unclear'**
7755+
String get autoSaveOnUnclearToggle;
77567756

7757-
/// No description provided for @autoFavoriteOnCantUnderstandSubtitle.
7757+
/// No description provided for @autoSaveOnUnclearSubtitle.
77587758
///
77597759
/// In en, this message translates to:
7760-
/// **'When on, tapping \"Hard to understand\" in intensive listening adds the sentence to favorites'**
7761-
String get autoFavoriteOnCantUnderstandSubtitle;
7760+
/// **'When on, tapping \"Unclear\" in intensive listening saves the sentence'**
7761+
String get autoSaveOnUnclearSubtitle;
7762+
7763+
/// No description provided for @unclearAutoSaveDialogTitle.
7764+
///
7765+
/// In en, this message translates to:
7766+
/// **'Auto-save unclear sentences'**
7767+
String get unclearAutoSaveDialogTitle;
7768+
7769+
/// No description provided for @unclearAutoSaveDialogMessage.
7770+
///
7771+
/// In en, this message translates to:
7772+
/// **'When you tap \"Unclear\", the sentence is saved automatically so you can review it later.'**
7773+
String get unclearAutoSaveDialogMessage;
7774+
7775+
/// No description provided for @unclearAutoSaveSwitchOn.
7776+
///
7777+
/// In en, this message translates to:
7778+
/// **'On'**
7779+
String get unclearAutoSaveSwitchOn;
7780+
7781+
/// No description provided for @unclearAutoSaveSwitchOff.
7782+
///
7783+
/// In en, this message translates to:
7784+
/// **'Off'**
7785+
String get unclearAutoSaveSwitchOff;
7786+
7787+
/// No description provided for @unclearAutoSaveDialogHint.
7788+
///
7789+
/// In en, this message translates to:
7790+
/// **'You can change this anytime in Me → Learning Settings.'**
7791+
String get unclearAutoSaveDialogHint;
7792+
7793+
/// No description provided for @unclearAutoSaveDialogConfirm.
7794+
///
7795+
/// In en, this message translates to:
7796+
/// **'Got it'**
7797+
String get unclearAutoSaveDialogConfirm;
77627798

77637799
/// No description provided for @retellSkip.
77647800
///

‎lib/l10n/app_localizations_en.dart‎

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,7 @@ class AppLocalizationsEn extends AppLocalizations {
13481348
String get intensiveListenHideSubtitle => 'Hide subtitles';
13491349

13501350
@override
1351-
String get intensiveListenCantUnderstand => 'Unclear';
1351+
String get intensiveListenUnclear => 'Unclear';
13521352

13531353
@override
13541354
String get intensiveListenAutoMarkedDifficult => 'Auto-save, tap to undo';
@@ -4433,12 +4433,31 @@ class AppLocalizationsEn extends AppLocalizations {
44334433
'When off, your recording can still be played back, but scores aren\'t shown';
44344434

44354435
@override
4436-
String get autoFavoriteOnCantUnderstandToggle =>
4437-
'Auto-favorite when marked as hard to understand';
4436+
String get autoSaveOnUnclearToggle => 'Auto-save when marked Unclear';
44384437

44394438
@override
4440-
String get autoFavoriteOnCantUnderstandSubtitle =>
4441-
'When on, tapping \"Hard to understand\" in intensive listening adds the sentence to favorites';
4439+
String get autoSaveOnUnclearSubtitle =>
4440+
'When on, tapping \"Unclear\" in intensive listening saves the sentence';
4441+
4442+
@override
4443+
String get unclearAutoSaveDialogTitle => 'Auto-save unclear sentences';
4444+
4445+
@override
4446+
String get unclearAutoSaveDialogMessage =>
4447+
'When you tap \"Unclear\", the sentence is saved automatically so you can review it later.';
4448+
4449+
@override
4450+
String get unclearAutoSaveSwitchOn => 'On';
4451+
4452+
@override
4453+
String get unclearAutoSaveSwitchOff => 'Off';
4454+
4455+
@override
4456+
String get unclearAutoSaveDialogHint =>
4457+
'You can change this anytime in Me → Learning Settings.';
4458+
4459+
@override
4460+
String get unclearAutoSaveDialogConfirm => 'Got it';
44424461

44434462
@override
44444463
String get retellSkip => 'Skip';

‎lib/l10n/app_localizations_zh.dart‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,7 +1308,7 @@ class AppLocalizationsZh extends AppLocalizations {
13081308
String get intensiveListenHideSubtitle => '隐藏字幕';
13091309

13101310
@override
1311-
String get intensiveListenCantUnderstand => '听不太懂';
1311+
String get intensiveListenUnclear => '听不太懂';
13121312

13131313
@override
13141314
String get intensiveListenAutoMarkedDifficult => '已自动收藏';
@@ -4229,10 +4229,28 @@ class AppLocalizationsZh extends AppLocalizations {
42294229
String get retellRatingSubtitle => '关闭后只保留录音回听,不再显示评分';
42304230

42314231
@override
4232-
String get autoFavoriteOnCantUnderstandToggle => '听不懂时自动收藏';
4232+
String get autoSaveOnUnclearToggle => '听不懂时自动收藏';
42334233

42344234
@override
4235-
String get autoFavoriteOnCantUnderstandSubtitle => '精听时点击「听不太懂」,自动把该句加入收藏';
4235+
String get autoSaveOnUnclearSubtitle => '精听时点击「听不太懂」,自动把该句加入收藏';
4236+
4237+
@override
4238+
String get unclearAutoSaveDialogTitle => '自动收藏听不懂的句子';
4239+
4240+
@override
4241+
String get unclearAutoSaveDialogMessage => '点「听不太懂」时,会自动收藏本句,方便你之后集中复习。';
4242+
4243+
@override
4244+
String get unclearAutoSaveSwitchOn => '开启';
4245+
4246+
@override
4247+
String get unclearAutoSaveSwitchOff => '关闭';
4248+
4249+
@override
4250+
String get unclearAutoSaveDialogHint => '随时可在「我的 → 学习设置」中修改。';
4251+
4252+
@override
4253+
String get unclearAutoSaveDialogConfirm => '知道了';
42364254

42374255
@override
42384256
String get retellSkip => '跳过';

‎lib/l10n/app_zh.arb‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@
545545
"intensiveListenPlayCount": "第 {current}/{total} 遍",
546546
"intensiveListenPeek": "偷看字幕",
547547
"intensiveListenHideSubtitle": "隐藏字幕",
548-
"intensiveListenCantUnderstand": "听不太懂",
548+
"intensiveListenUnclear": "听不太懂",
549549
"intensiveListenAutoMarkedDifficult": "已自动收藏",
550550
"intensiveListenMarkedDifficult": "取消收藏",
551551
"intensiveListenNotDifficult": "收藏",
@@ -1818,8 +1818,14 @@
18181818
"listenAndRepeatRatingSubtitle": "关闭后保留录音回听,但不再识别和评分",
18191819
"retellRatingToggle": "复述时显示评分",
18201820
"retellRatingSubtitle": "关闭后只保留录音回听,不再显示评分",
1821-
"autoFavoriteOnCantUnderstandToggle": "听不懂时自动收藏",
1822-
"autoFavoriteOnCantUnderstandSubtitle": "精听时点击「听不太懂」,自动把该句加入收藏",
1821+
"autoSaveOnUnclearToggle": "听不懂时自动收藏",
1822+
"autoSaveOnUnclearSubtitle": "精听时点击「听不太懂」,自动把该句加入收藏",
1823+
"unclearAutoSaveDialogTitle": "自动收藏听不懂的句子",
1824+
"unclearAutoSaveDialogMessage": "点「听不太懂」时,会自动收藏本句,方便你之后集中复习。",
1825+
"unclearAutoSaveSwitchOn": "开启",
1826+
"unclearAutoSaveSwitchOff": "关闭",
1827+
"unclearAutoSaveDialogHint": "随时可在「我的 → 学习设置」中修改。",
1828+
"unclearAutoSaveDialogConfirm": "知道了",
18231829
"retellSkip": "跳过",
18241830
"retellSkippedSuffix": "已跳过",
18251831
"skipSilenceTitle": "自动跳过静音",

‎lib/providers/learning_session/intensive_listen_player_provider.dart‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -479,21 +479,21 @@ class IntensiveListenPlayer extends _$IntensiveListenPlayer {
479479

480480
// 「听不太懂」自动收藏受学习设置控制;关闭时只进入讲解,不改收藏状态。
481481
// 持久化靠对比 difficultSentences 完成,因此不加入即不写库。
482-
final autoFavoriteEnabled = ref
482+
final autoSaveEnabled = ref
483483
.read(learningSettingsProvider)
484-
.autoFavoriteOnCantUnderstand;
484+
.autoSaveOnUnclear;
485485
final newDifficult = Set<int>.from(state.difficultSentences);
486486
final wasAlreadyDifficult = newDifficult.contains(
487487
state.currentSentenceIndex,
488488
);
489-
final shouldAutoFavorite = autoFavoriteEnabled && !wasAlreadyDifficult;
490-
if (shouldAutoFavorite) {
489+
final shouldAutoSave = autoSaveEnabled && !wasAlreadyDifficult;
490+
if (shouldAutoSave) {
491491
newDifficult.add(state.currentSentenceIndex);
492492
}
493493

494494
state = state.copyWith(
495495
difficultSentences: newDifficult,
496-
isCurrentSentenceAutoMarked: shouldAutoFavorite,
496+
isCurrentSentenceAutoMarked: shouldAutoSave,
497497
isTextRevealed: false,
498498
playingSenseGroupIndex: null,
499499
playedSenseGroupIndices: const {},

0 commit comments

Comments
 (0)