feat(ui): a question mark that keeps a section's explanation one tap away
HelpButton, beside a section's or a setting's title: the explanation opens in a small dialog, under its title where given, rather than standing in the everyday view (the developer's review of 3 Nov 2026). FieldInfoButton's tooltip stays for a field's short hint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
abac248b76
commit
55fc245859
8 changed files with 85 additions and 3 deletions
|
|
@ -26,6 +26,7 @@ export 'src/widget/field_label.dart';
|
||||||
export 'src/widget/floating_navigation_bar.dart';
|
export 'src/widget/floating_navigation_bar.dart';
|
||||||
export 'src/widget/folding_tabs.dart';
|
export 'src/widget/folding_tabs.dart';
|
||||||
export 'src/widget/found_by_id.dart';
|
export 'src/widget/found_by_id.dart';
|
||||||
|
export 'src/widget/help_button.dart';
|
||||||
export 'src/widget/keyboard_back_on_resume.dart';
|
export 'src/widget/keyboard_back_on_resume.dart';
|
||||||
export 'src/widget/launch_screen.dart';
|
export 'src/widget/launch_screen.dart';
|
||||||
export 'src/widget/lift_while_dragged.dart';
|
export 'src/widget/lift_while_dragged.dart';
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"@@locale": "de",
|
"@@locale": "de",
|
||||||
|
|
||||||
"brand": "Halkyon",
|
"brand": "Halkyon",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
|
|
@ -17,5 +16,6 @@
|
||||||
"copiedToClipboard": "In die Zwischenablage kopiert",
|
"copiedToClipboard": "In die Zwischenablage kopiert",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
"paletteColorName": "{name, select, carrot{Karotte} cerise{Kirschrot} cobalt{Kobalt} copper{Kupfer} enzian{Enzian} fern{Farn} forest{Wald} ocean{Ozean} olive{Olive} pacific{Pazifik} pickle{Essiggurke} pine{Kiefer} pink{Rosa} plum{Pflaume} purple{Lila} reef{Riff} sahara{Sahara} slateblue{Schieferblau} soil{Erde} strawberry{Erdbeere} other{{name}}}",
|
"paletteColorName": "{name, select, carrot{Karotte} cerise{Kirschrot} cobalt{Kobalt} copper{Kupfer} enzian{Enzian} fern{Farn} forest{Wald} ocean{Ozean} olive{Olive} pacific{Pazifik} pickle{Essiggurke} pine{Kiefer} pink{Rosa} plum{Pflaume} purple{Lila} reef{Riff} sahara{Sahara} slateblue{Schieferblau} soil{Erde} strawberry{Erdbeere} other{{name}}}",
|
||||||
"colorPickerLabel": "Farbe: {color}"
|
"colorPickerLabel": "Farbe: {color}",
|
||||||
|
"explain": "Was ist das?"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"@@locale": "en",
|
"@@locale": "en",
|
||||||
|
|
||||||
"brand": "Halkyon",
|
"brand": "Halkyon",
|
||||||
"@brand": {
|
"@brand": {
|
||||||
"description": "The brand's word, above an app's own in its wordmark (\"Halkyon\" over \"Learn\")."
|
"description": "The brand's word, above an app's own in its wordmark (\"Halkyon\" over \"Learn\")."
|
||||||
|
|
@ -38,5 +37,9 @@
|
||||||
"type": "String"
|
"type": "String"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"explain": "What's this?",
|
||||||
|
"@explain": {
|
||||||
|
"description": "Tooltip of the question mark that opens a text explaining a section or setting (HelpButton)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,12 @@ abstract class HalkyonUiLocalizations {
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Colour: {color}'**
|
/// **'Colour: {color}'**
|
||||||
String colorPickerLabel(String color);
|
String colorPickerLabel(String color);
|
||||||
|
|
||||||
|
/// Tooltip of the question mark that opens a text explaining a section or setting (HelpButton).
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'What\'s this?'**
|
||||||
|
String get explain;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HalkyonUiLocalizationsDelegate
|
class _HalkyonUiLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -90,4 +90,7 @@ class HalkyonUiLocalizationsDe extends HalkyonUiLocalizations {
|
||||||
String colorPickerLabel(String color) {
|
String colorPickerLabel(String color) {
|
||||||
return 'Farbe: $color';
|
return 'Farbe: $color';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get explain => 'Was ist das?';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,9 @@ class HalkyonUiLocalizationsEn extends HalkyonUiLocalizations {
|
||||||
String colorPickerLabel(String color) {
|
String colorPickerLabel(String color) {
|
||||||
return 'Colour: $color';
|
return 'Colour: $color';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get explain => 'What\'s this?';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The translations for English, as used in the United Kingdom (`en_GB`).
|
/// The translations for English, as used in the United Kingdom (`en_GB`).
|
||||||
|
|
|
||||||
37
packages/halkyon_ui/lib/src/widget/help_button.dart
Normal file
37
packages/halkyon_ui/lib/src/widget/help_button.dart
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import 'package:halkyon_ui/l10n/halkyon_ui_localizations.dart';
|
||||||
|
import 'package:halkyon_ui/src/widget/field_label.dart';
|
||||||
|
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||||
|
import 'package:material_ui/material_ui.dart';
|
||||||
|
|
||||||
|
/// A question mark beside a section's or a setting's title that keeps its
|
||||||
|
/// explanation out of the everyday view: a tap opens [message] in a small
|
||||||
|
/// dialog, under [title] where given (decided 3 Nov 2026: what explains,
|
||||||
|
/// rather than what is the person's own, is one tap away). For a field's
|
||||||
|
/// short hint, [FieldInfoButton]'s tooltip.
|
||||||
|
class const HelpButton(
|
||||||
|
final String message, {
|
||||||
|
final String? title,
|
||||||
|
super.key,
|
||||||
|
}) extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => IconButton(
|
||||||
|
icon: const Icon(LucideIcons.circleQuestionMark, size: 20),
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
tooltip: HalkyonUiLocalizations.of(context).explain,
|
||||||
|
onPressed: () => showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
icon: const Icon(LucideIcons.circleQuestionMark),
|
||||||
|
title: title == null ? null : Text(title!),
|
||||||
|
content: SingleChildScrollView(child: Text(message)),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: Text(MaterialLocalizations.of(context).okButtonLabel),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
29
packages/halkyon_ui/test/widget/help_button_test.dart
Normal file
29
packages/halkyon_ui/test/widget/help_button_test.dart
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||||
|
import 'package:material_ui/material_ui.dart';
|
||||||
|
|
||||||
|
import '../support/test_app.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('the explanation stays hidden until the question mark is '
|
||||||
|
'tapped, then shows under its title and closes again', (tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
testApp(
|
||||||
|
const Scaffold(
|
||||||
|
body: HelpButton('How sources are cited.', title: 'Citation style'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(find.text('How sources are cited.'), findsNothing);
|
||||||
|
expect(find.byTooltip("What's this?"), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.byType(HelpButton));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Citation style'), findsOneWidget);
|
||||||
|
expect(find.text('How sources are cited.'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('OK'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('How sources are cited.'), findsNothing);
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue