feat(learn,app): explanations wait behind a question mark beside their title
What explains a setting or a section, rather than what is the person's own, moves behind halkyon_ui's HelpButton, beside its title through the new ExplainedTitle (the developer's review of 3 Nov 2026): in Learn's settings (citations, the Pomodoro timer, grammar, the web search, Jellyfin, the device's dictionaries, counting one's learning), the study settings, export's progress, the Jellyfin tags and the study button's back first; in halkyon_app, setting up a password, adding SimpleLogin, own keys not allowed, the profile page's link back and the operator's grant sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
c984678c5b
commit
830aea10fe
10 changed files with 279 additions and 115 deletions
|
|
@ -33,9 +33,10 @@ class const AssistantSettingsCard({super.key}) extends StatelessWidget {
|
|||
),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(l10n.settingsAskAssistant),
|
||||
subtitle: Text(l10n.settingsAskAssistantSubtitle),
|
||||
isThreeLine: true,
|
||||
title: ExplainedTitle(
|
||||
l10n.settingsAskAssistant,
|
||||
help: l10n.settingsAskAssistantSubtitle,
|
||||
),
|
||||
value: on,
|
||||
onChanged: (on) => context.read<DeviceSettingsBloc>().add(
|
||||
DeviceSettingsEventAssistantChosen(on),
|
||||
|
|
|
|||
|
|
@ -186,15 +186,14 @@ class const _SettingsCard() extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
ExplainedTitle(
|
||||
l10n.settingsDeviceDictionaryTitle,
|
||||
help: l10n.settingsDeviceDictionaryAbout,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(l10n.settingsDeviceDictionaryAbout),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 8),
|
||||
if (dictionaries.progress case final progress?)
|
||||
DeviceDictionaryProgressView(progress: progress)
|
||||
else if (installed != null)
|
||||
|
|
|
|||
|
|
@ -256,8 +256,10 @@ class _ExportSheetState() extends State<_ExportSheet> {
|
|||
value: _withProgress,
|
||||
onChanged: (value) =>
|
||||
setState(() => _withProgress = value ?? _withProgress),
|
||||
title: Text(l10n.exportWithProgress),
|
||||
subtitle: Text(l10n.exportWithProgressSubtitle),
|
||||
title: ExplainedTitle(
|
||||
l10n.exportWithProgress,
|
||||
help: l10n.exportWithProgressSubtitle,
|
||||
),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -159,15 +159,16 @@ class _JellyfinBrowserScreenState() extends State<JellyfinBrowserScreen> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(l10n.jellyfinSubtitle),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l10n.jellyfinPrivacy,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
ExplainedTitle(
|
||||
l10n.jellyfinTitle,
|
||||
help:
|
||||
'${l10n.jellyfinSubtitle}\n\n'
|
||||
'${l10n.jellyfinPrivacy}',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 8),
|
||||
const JellyfinConnectForm(),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -14,22 +14,14 @@ class const JellyfinSettingsCard({super.key}) extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
ExplainedTitle(
|
||||
l10n.jellyfinTitle,
|
||||
help: '${l10n.jellyfinSubtitle}\n\n${l10n.jellyfinPrivacy}',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(l10n.jellyfinSubtitle),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l10n.jellyfinPrivacy,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 8),
|
||||
const JellyfinAccountView(),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -30,20 +30,14 @@ class const CitationSettingsCard({super.key}) extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
ExplainedTitle(
|
||||
l10n.settingsCitations,
|
||||
help: l10n.settingsCitationsDescription,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l10n.settingsCitationsDescription,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 8),
|
||||
DropdownButtonFormField<CitationStyle>(
|
||||
initialValue: style,
|
||||
// A style's name is cut short rather than overflowing a phone.
|
||||
|
|
|
|||
|
|
@ -177,9 +177,10 @@ class const _PrivacyCard() extends StatelessWidget {
|
|||
),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(l10n.settingsCountLearning),
|
||||
subtitle: Text(l10n.settingsCountLearningSubtitle),
|
||||
isThreeLine: true,
|
||||
title: ExplainedTitle(
|
||||
l10n.settingsCountLearning,
|
||||
help: l10n.settingsCountLearningSubtitle,
|
||||
),
|
||||
value: counted ?? false,
|
||||
onChanged: counted == null
|
||||
? null
|
||||
|
|
@ -221,8 +222,10 @@ class const _StudyCard() extends StatelessWidget {
|
|||
),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(l10n.settingsStudyPomodoroTitle),
|
||||
subtitle: Text(l10n.settingsStudyPomodoroSubtitle),
|
||||
title: ExplainedTitle(
|
||||
l10n.settingsStudyPomodoroTitle,
|
||||
help: l10n.settingsStudyPomodoroSubtitle,
|
||||
),
|
||||
value: context.select<DeviceSettingsBloc, bool>(
|
||||
(bloc) => bloc.state.pomodoroWhileStudying,
|
||||
),
|
||||
|
|
@ -270,9 +273,10 @@ class _WritingCardState() extends State<_WritingCard> {
|
|||
),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(l10n.settingsGrammarTitle),
|
||||
subtitle: Text(l10n.settingsGrammarSubtitle),
|
||||
isThreeLine: true,
|
||||
title: ExplainedTitle(
|
||||
l10n.settingsGrammarTitle,
|
||||
help: l10n.settingsGrammarSubtitle,
|
||||
),
|
||||
value: context.select<DeviceSettingsBloc, bool>(
|
||||
(bloc) => bloc.state.checkGrammar,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -346,8 +346,10 @@ class _StudyButtonDialogState() extends State<_StudyButtonDialog> {
|
|||
),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(l10n.studyButtonBackFirst),
|
||||
subtitle: Text(l10n.studyButtonBackFirstHelper),
|
||||
title: ExplainedTitle(
|
||||
l10n.studyButtonBackFirst,
|
||||
help: l10n.studyButtonBackFirstHelper,
|
||||
),
|
||||
value: _backFirst,
|
||||
onChanged: (value) =>
|
||||
setState(() => _backFirst = value),
|
||||
|
|
|
|||
|
|
@ -240,14 +240,16 @@ class const _Options({required final StudyOptions options})
|
|||
value: mode,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: Text(switch (mode) {
|
||||
LearnMode.spaced => l10n.studyModeSpaced,
|
||||
LearnMode.cram => l10n.studyModeCram,
|
||||
}),
|
||||
subtitle: Text(switch (mode) {
|
||||
LearnMode.spaced => l10n.studyModeSpacedHint,
|
||||
LearnMode.cram => l10n.studyModeCramHint,
|
||||
}),
|
||||
title: switch (mode) {
|
||||
LearnMode.spaced => ExplainedTitle(
|
||||
l10n.studyModeSpaced,
|
||||
help: l10n.studyModeSpacedHint,
|
||||
),
|
||||
LearnMode.cram => ExplainedTitle(
|
||||
l10n.studyModeCram,
|
||||
help: l10n.studyModeCramHint,
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -265,8 +267,12 @@ class const _Options({required final StudyOptions options})
|
|||
),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: Text(l10n.studySettingsQuizMc),
|
||||
subtitle: Text(l10n.studySettingsQuizMcDescription),
|
||||
title: ExplainedTitle(
|
||||
l10n.studySettingsQuizMc,
|
||||
help:
|
||||
'${l10n.studySettingsQuizMcDescription}\n\n'
|
||||
'${l10n.studySettingsAspectDescription}',
|
||||
),
|
||||
),
|
||||
if (options.quizVocabulary) ...[
|
||||
const SizedBox(height: 8),
|
||||
|
|
@ -289,13 +295,6 @@ class const _Options({required final StudyOptions options})
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l10n.studySettingsAspectDescription,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
SwitchListTile(
|
||||
value: options.typeReadings,
|
||||
|
|
@ -307,8 +306,10 @@ class const _Options({required final StudyOptions options})
|
|||
),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: Text(l10n.studySettingsTypeReading),
|
||||
subtitle: Text(l10n.studySettingsTypeReadingDescription),
|
||||
title: ExplainedTitle(
|
||||
l10n.studySettingsTypeReading,
|
||||
help: l10n.studySettingsTypeReadingDescription,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(l10n.studySettingsCharacters, style: heading),
|
||||
|
|
@ -318,8 +319,10 @@ class const _Options({required final StudyOptions options})
|
|||
onChanged: (write) => change(options.copyWith(writeByHand: write)),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: Text(l10n.studySettingsWriteByHand),
|
||||
subtitle: Text(l10n.studySettingsWriteByHandDescription),
|
||||
title: ExplainedTitle(
|
||||
l10n.studySettingsWriteByHand,
|
||||
help: l10n.studySettingsWriteByHandDescription,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -106,8 +106,10 @@ class const _HideJellyfinTags() extends StatelessWidget {
|
|||
final l10n = AppLocalizations.of(context);
|
||||
return SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(l10n.tagManageHideJellyfin),
|
||||
subtitle: Text(l10n.tagManageHideJellyfinHint),
|
||||
title: ExplainedTitle(
|
||||
l10n.tagManageHideJellyfin,
|
||||
help: l10n.tagManageHideJellyfinHint,
|
||||
),
|
||||
value: context.watch<JellyfinTagsBloc>().state ?? false,
|
||||
onChanged: (hidden) => context.read<JellyfinTagsBloc>().add(
|
||||
JellyfinTagsEventHidingChosen(hidden),
|
||||
|
|
|
|||
Loading…
Reference in a new issue