fix(map): a region is picked on a screen of its own, and a country's map offered once it is picked

The composer showed the map inside its scrolling page, so zooming and
scrolling fought over the wheel. A map question's answer is now a field
that opens the map in the whole window, as a studyset's description is
written, with Save in the app bar; nothing scrolls there, so the wheel
alone zooms. The Prefectures chip stood beside East Asia's countries
before Japan was picked; it now shows once Japan, or a prefecture, is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-12 18:02:15 +02:00
commit 3181223940
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
12 changed files with 327 additions and 110 deletions

View file

@ -925,6 +925,7 @@
"mapUnknown": "Diese Landkarte braucht eine neuere Version der App.",
"mapPickRegion": "Wähle einen Teil der Karte, dann tippe auf die Region, die die Frage beantwortet. Winzige Orte haben einen Ring; wo Ringe dicht liegen, zoome hinein.",
"mapNonePicked": "Noch keine Region gewählt",
"mapPickTitle": "Region wählen",
"mapNameJapan": "Japan",
"mapNameWorld": "Welt",
"mapPrefectures": "Präfekturen",
@ -951,6 +952,7 @@
"mapGroupOceania": "Ozeanien",
"composerPlaceholderQuestion": "Frage hinzufügen",
"composerLabelRegion": "Antwort",
"composerRegionPick": "Tippen, um die Region auf der Karte zu wählen",
"homeStreakTooltip": "Lernserie",
"homeArrange": "Widgets anordnen",

View file

@ -1030,6 +1030,7 @@
"mapUnknown": "This map needs a newer version of the app.",
"mapPickRegion": "Choose a part of the map, then tap the region that answers the question. Tiny places have a ring; where rings crowd, zoom in.",
"mapNonePicked": "No region picked yet",
"mapPickTitle": "Pick the region",
"mapNameJapan": "Japan",
"mapNameWorld": "World",
"mapPrefectures": "Prefectures",
@ -1056,6 +1057,7 @@
"mapGroupOceania": "Oceania",
"composerPlaceholderQuestion": "Add question",
"composerLabelRegion": "Answer",
"composerRegionPick": "Tap to pick the region on the map",
"homeStreakTooltip": "Study streak",
"homeArrange": "Arrange widgets",

View file

@ -5458,6 +5458,12 @@ abstract class AppLocalizations {
/// **'No region picked yet'**
String get mapNonePicked;
/// No description provided for @mapPickTitle.
///
/// In en, this message translates to:
/// **'Pick the region'**
String get mapPickTitle;
/// No description provided for @mapNameJapan.
///
/// In en, this message translates to:
@ -5614,6 +5620,12 @@ abstract class AppLocalizations {
/// **'Answer'**
String get composerLabelRegion;
/// No description provided for @composerRegionPick.
///
/// In en, this message translates to:
/// **'Tap to pick the region on the map'**
String get composerRegionPick;
/// No description provided for @homeStreakTooltip.
///
/// In en, this message translates to:

View file

@ -3419,6 +3419,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get mapNonePicked => 'Noch keine Region gewählt';
@override
String get mapPickTitle => 'Region wählen';
@override
String get mapNameJapan => 'Japan';
@ -3497,6 +3500,10 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get composerLabelRegion => 'Antwort';
@override
String get composerRegionPick =>
'Tippen, um die Region auf der Karte zu wählen';
@override
String get homeStreakTooltip => 'Lernserie';

View file

@ -3393,6 +3393,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get mapNonePicked => 'No region picked yet';
@override
String get mapPickTitle => 'Pick the region';
@override
String get mapNameJapan => 'Japan';
@ -3471,6 +3474,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get composerLabelRegion => 'Answer';
@override
String get composerRegionPick => 'Tap to pick the region on the map';
@override
String get homeStreakTooltip => 'Study streak';

View file

@ -0,0 +1,65 @@
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:material_ui/material_ui.dart';
/// A form's field whose value is set on a screen of its own: it shows the
/// [value], up to [maxLines] lines, or the [placeholder] in italics while
/// there is none, and a chevron leads on, as tapping opens that screen.
/// So the form never holds what needs a whole window (an editor, a map).
class const ChevronField({
/// What the field holds, above it.
required final String label,
/// The value as text; null while there is none.
required final String? value,
/// What shows while there is no value, inviting to set one.
required final String placeholder,
/// Opens the screen that sets the value.
required final VoidCallback onTap,
final int maxLines = 3,
super.key,
}) extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colors = theme.colorScheme;
return InputDecorator(
decoration: InputDecoration(
labelText: label,
border: const OutlineInputBorder(),
contentPadding: const EdgeInsets.fromLTRB(12, 12, 4, 12),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(4),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
Expanded(
child: Text(
value ?? placeholder,
maxLines: maxLines,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium?.copyWith(
color: value == null
? colors.onSurfaceVariant
: colors.onSurface,
fontStyle: value == null ? FontStyle.italic : null,
),
),
),
const SizedBox(width: 8),
Icon(
LucideIcons.chevronRight,
size: 18,
color: colors.onSurfaceVariant,
),
],
),
),
),
);
}
}

View file

@ -4,6 +4,7 @@ import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_view.dart';
import 'package:halkyon_learn_flutter/src/core/widget/chevron_field.dart';
import 'package:halkyon_learn_flutter/src/feature/card/bloc/card_composer_bloc.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
import 'package:halkyon_learn_flutter/src/feature/card/widget/composer/answers_editor.dart';
@ -18,8 +19,8 @@ import 'package:halkyon_learn_flutter/src/feature/dictionary/widget/studyset_dic
import 'package:halkyon_learn_flutter/src/feature/geo_map/data/geo_map_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/model/geo_map.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/widget/map_of.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/widget/region_map.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/widget/region_names.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/widget/region_picker.dart';
import 'package:halkyon_learn_flutter/src/feature/tag/model/tag.dart';
import 'package:halkyon_learn_flutter/src/feature/tag/model/tagging.dart';
import 'package:halkyon_learn_flutter/src/feature/tag/widget/tag_chip.dart';
@ -578,8 +579,9 @@ class _CardDraftEditorState() extends State<CardDraftEditor> {
}
}
/// A map question's answer: the region to point at, picked on the maps
/// as one, from the layer the studyset's other map questions share.
/// A map question's answer: the region to point at, as a field that opens
/// the maps as one in the whole window ([pickRegion]), from the region
/// picked or the layer the studyset's other map questions share.
class const _MapAnswer({
required final CardContent content,
required final Set<String> around,
@ -590,50 +592,20 @@ class const _MapAnswer({
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final theme = Theme.of(context);
final picked = content.answers.firstOrNull?.region;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(l10n.composerLabelRegion, style: theme.textTheme.labelLarge),
const SizedBox(height: 4),
Text(
l10n.mapPickRegion,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 8),
MapOf(
builder: (context, atlas) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
RegionMap(
atlas: atlas,
selected: picked,
around: around,
onRegionTapped: (code) =>
onPicked(atlas.mapOf(code)!, atlas.region(code)!),
),
const SizedBox(height: 8),
Text(
switch (atlas.region(picked)) {
final region? => switch (regionOtherName(
context,
atlas.mapOf(picked)!,
region,
)) {
final other? => '${regionName(context, region)} · $other',
null => regionName(context, region),
},
null => l10n.mapNonePicked,
},
style: theme.textTheme.titleSmall,
),
],
),
),
],
return MapOf(
builder: (context, atlas) => ChevronField(
label: l10n.composerLabelRegion,
value: pickedRegionName(context, atlas, picked),
placeholder: l10n.composerRegionPick,
maxLines: 1,
onTap: () async {
if (await pickRegion(context, initial: picked, around: around)
case final code? when code != picked) {
onPicked(atlas.mapOf(code)!, atlas.region(code)!);
}
},
),
);
}
}

View file

@ -16,8 +16,9 @@ import 'package:material_ui/material_ui.dart';
/// What tapping a country with a map of its own (Japan: its prefectures)
/// does.
enum CountryTaps() {
/// Picks the country, and a chip opens its map: while writing a
/// question, which may be about either.
/// Picks the country, and once it or a region within it is picked, a
/// chip opens its map: while writing a question, which may be about
/// either.
pickOrOpen,
/// Picks the country: a question about the country.
@ -33,7 +34,9 @@ enum CountryTaps() {
/// its own, its prefectures, in groups too (Kantō, Kansai …), which opens
/// from Japan as [countryTaps] says. Back goes up a layer. So a region one
/// can hardly hit on a phone is picked where it is large enough: Cyprus in
/// Europe rather than on the world, Tokyo in Kantō.
/// Europe rather than on the world, Tokyo in Kantō. A country's own map is
/// offered only once the country is picked, so the prefectures don't stand
/// beside East Asia's other countries as if they were one.
///
/// Even there some are too small to hit (Liechtenstein, Malta, the
/// Caribbean's islands): they get a ring, which picks them. A tap picks the
@ -42,7 +45,7 @@ enum CountryTaps() {
/// the least a finger is sure to hit) or outline within 8 dp. Where rings
/// crowd, one zooms in, on any layer: pinching, or scrolling with Ctrl (⌘
/// on a Mac) held, as maps on web pages do, so plain scrolling still scrolls
/// the page; scrolling without it says so. Drags pan. In a page that
/// the page; scrolling without it says so, unless [wheelZooms]. Drags pan. In a page that
/// scrolls, the map is 4:3 but never taller than
/// [RegionMapState.screenShare] of the screen, so all of it shows while
/// zooming.
@ -76,6 +79,10 @@ class const RegionMap({
/// The region picked wrongly, once checked.
final String? wrong,
/// Whether the mouse's wheel zooms without Ctrl (or ⌘): where nothing
/// around the map scrolls.
final bool wheelZooms = false,
super.key,
}) extends StatefulWidget {
@override
@ -165,6 +172,16 @@ class RegionMapState()
_MapGeometry _geometryOf(GeoMap map) =>
_geometries[map] ??= _MapGeometry(map);
/// Whether the region picked is [country] or lies within it: only then
/// does a chip offer the country's own map.
bool _pickedIn(String country) => switch (widget.atlas.mapOf(
widget.selected,
)) {
null => false,
final map =>
widget.selected == country || widget.atlas.countryOf(map) == country,
};
/// Whether a tap picks a region here, rather than a group.
bool get _picksRegions => _level.group != null || _level.map.groups.isEmpty;
@ -355,13 +372,14 @@ class RegionMapState()
/// A mouse's wheel with Ctrl (or ⌘) held zooms around the pointer, as
/// pinching does, and the page around doesn't scroll; without, the page
/// scrolls and a note says how to zoom.
/// scrolls and a note says how to zoom. Where nothing around scrolls
/// ([RegionMap.wheelZooms]), the wheel alone zooms.
void _scrolled(PointerSignalEvent event) {
if (event is! PointerScrollEvent || _view == null || _size == null) {
return;
}
final keys = HardwareKeyboard.instance;
if (!keys.isControlPressed && !keys.isMetaPressed) {
if (!widget.wheelZooms && !keys.isControlPressed && !keys.isMetaPressed) {
_noteZoomKeys();
return;
}
@ -496,7 +514,8 @@ class RegionMapState()
if (widget.countryTaps == CountryTaps.pickOrOpen &&
_level.group != null)
for (final MapEntry(key: country, value: map) in atlas.inside.entries)
if (_level.group!.members.contains(country)) map,
if (_level.group!.members.contains(country) && _pickedIn(country))
map,
],
onBack: above == null ? null : () => _open(above),
onChoose: _choose,
@ -529,7 +548,8 @@ class RegionMapState()
/// Above the map: Back to the layer [above], if any; on a whole map a chip
/// per group, which opens it; in a group its name, and a chip for each map
/// within a country of it that one may [opens] (Japan's prefectures).
/// within a country of it that one may [opens] (Japan's prefectures, once
/// Japan is picked).
class const _Header({
required final MapLevel level,
required final MapLevel? above,

View file

@ -0,0 +1,107 @@
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/model/atlas.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/widget/map_of.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/widget/region_map.dart';
import 'package:halkyon_learn_flutter/src/feature/geo_map/widget/region_names.dart';
import 'package:material_ui/material_ui.dart';
/// Picks a region on the maps in the whole window, over what opened it, as
/// a studyset's description is written: the map fills what the window
/// leaves, so nothing around it scrolls and the wheel alone zooms. Opens on
/// the region [initial], else around the regions [around]; completes with
/// the code of the region picked once saved, or with null when left
/// without saving.
Future<String?> pickRegion(
BuildContext context, {
required String? initial,
Set<String> around = const {},
}) => Navigator.of(context).push<String>(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => _RegionPicker(initial: initial, around: around),
),
);
class const _RegionPicker({
required final String? initial,
required final Set<String> around,
}) extends StatefulWidget {
@override
State<_RegionPicker> createState() => _RegionPickerState();
}
class _RegionPickerState() extends State<_RegionPicker> {
late var _picked = widget.initial;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Text(l10n.mapPickTitle),
actions: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: FilledButton(
onPressed: _picked == null
? null
: () => Navigator.of(context).pop(_picked),
child: Text(l10n.commonSave),
),
),
],
),
body: SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: MapOf(
builder: (context, atlas) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
l10n.mapPickRegion,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 12),
Expanded(
child: RegionMap(
atlas: atlas,
selected: _picked,
around: widget.around,
wheelZooms: true,
onRegionTapped: (code) => setState(() => _picked = code),
),
),
const SizedBox(height: 12),
Text(
pickedRegionName(context, atlas, _picked) ??
l10n.mapNonePicked,
style: theme.textTheme.titleSmall,
),
],
),
),
),
),
);
}
}
/// The region [code] by its name, with its other name after a dot where
/// it has one (Tokyo · 東京都); null for none.
String? pickedRegionName(BuildContext context, Atlas atlas, String? code) =>
switch (atlas.region(code)) {
final region? => switch (regionOtherName(
context,
atlas.mapOf(code)!,
region,
)) {
final other? => '${regionName(context, region)} · $other',
null => regionName(context, region),
},
null => null,
};

View file

@ -6,6 +6,7 @@ import 'package:halkyon_learn_flutter/src/core/editor/rich_text_screen.dart';
import 'package:halkyon_learn_flutter/src/core/l10n/content_languages.dart';
import 'package:halkyon_learn_flutter/src/core/theme/palette_color.dart';
import 'package:halkyon_learn_flutter/src/core/widget/adaptive_sheet.dart';
import 'package:halkyon_learn_flutter/src/core/widget/chevron_field.dart';
import 'package:halkyon_learn_flutter/src/core/widget/confirm_dialog.dart';
import 'package:halkyon_learn_flutter/src/core/widget/field_label.dart';
import 'package:halkyon_learn_flutter/src/core/widget/palette_color_picker.dart';
@ -590,48 +591,16 @@ class const _DescriptionField({
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final theme = Theme.of(context);
final colors = theme.colorScheme;
final text = description.plainText.trim();
final empty = description.isBlank;
return InputDecorator(
decoration: InputDecoration(
labelText: l10n.studysetSheetDescription,
border: const OutlineInputBorder(),
contentPadding: const EdgeInsets.fromLTRB(12, 12, 4, 12),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(4),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
Expanded(
child: Text(
empty
? l10n.studysetSheetDescriptionAdd
: text.isNotEmpty
? text
: l10n.studysetSheetDescriptionAdded,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium?.copyWith(
color: empty ? colors.onSurfaceVariant : colors.onSurface,
fontStyle: empty ? FontStyle.italic : null,
),
),
),
const SizedBox(width: 8),
Icon(
LucideIcons.chevronRight,
size: 18,
color: colors.onSurfaceVariant,
),
],
),
),
),
return ChevronField(
label: l10n.studysetSheetDescription,
value: description.isBlank
? null
: text.isNotEmpty
? text
: l10n.studysetSheetDescriptionAdded,
placeholder: l10n.studysetSheetDescriptionAdd,
onTap: onTap,
);
}
}

View file

@ -6,6 +6,7 @@ import 'package:halkyon_learn_flutter/src/core/content/content_blocks.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/core/widget/chevron_field.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
@ -122,6 +123,12 @@ void main() {
await settle(tester);
}
/// Opens the map from a map question's answer.
Future<void> pickOnMap(WidgetTester tester) async {
await tester.tap(find.byType(ChevronField));
await settle(tester);
}
/// Chooses [item] of the card's ⋮ menu.
Future<void> action(WidgetTester tester, String item) async {
await tester.tap(find.byTooltip('More actions'));
@ -637,19 +644,32 @@ void main() {
expect(saved.back, RichContent.empty());
});
testWidgets('a map question takes the region tapped as its answer', (
tester,
) async {
testWidgets('a map question takes the region tapped on a screen of its '
'own, where nothing scrolls, as its answer once saved', (tester) async {
await cards.create('japanese', card('Where is Tokyo?', 'east'));
await showStudyset(tester, maps: await loadedMaps(tester));
await open(tester, 'Where is Tokyo?');
await tester.tap(find.text('Map'));
await settle(tester);
expect(find.byType(RegionMap), findsNothing);
await pickOnMap(tester);
expect(find.text('No region picked yet'), findsOneWidget);
expect(
find.ancestor(
of: find.byType(RegionMap),
matching: find.byType(Scrollable),
),
findsNothing,
);
expect(tester.widget<RegionMap>(find.byType(RegionMap)).wheelZooms, true);
tester.widget<RegionMap>(find.byType(RegionMap)).onRegionTapped!('JP-13');
await settle(tester);
expect(find.text('Tokyo · 東京都'), findsOneWidget);
await tester.tap(find.widgetWithText(FilledButton, 'Save'));
await settle(tester);
expect(find.byType(RegionMap), findsNothing);
expect(find.text('Tokyo · 東京都'), findsOneWidget);
await tester.tap(find.byType(BackButton));
await settle(tester);
@ -676,10 +696,13 @@ void main() {
await tester.tap(find.text('Map'));
await settle(tester);
expect(find.text('Countries of the world'), findsNothing);
await pickOnMap(tester);
tester.widget<RegionMap>(find.byType(RegionMap)).onRegionTapped!('JP-13');
await settle(tester);
tester.widget<RegionMap>(find.byType(RegionMap)).onRegionTapped!('CY');
await settle(tester);
await tester.tap(find.widgetWithText(FilledButton, 'Save'));
await settle(tester);
// Beside the app's language, the studyset's: Japanese.
expect(find.text('Cyprus · キプロス'), findsOneWidget);
await tester.tap(find.byType(BackButton));
@ -720,6 +743,7 @@ void main() {
await tester.tap(find.text('Map'));
await settle(tester);
await pickOnMap(tester);
expect(tester.widget<RegionMap>(find.byType(RegionMap)).around, {
'JP-13',
@ -731,4 +755,23 @@ void main() {
findsOneWidget,
);
});
testWidgets('leaving the map without saving keeps the answer', (
tester,
) async {
await cards.create('japanese', card('Where is Tokyo?', 'east'));
await showStudyset(tester, maps: await loadedMaps(tester));
await open(tester, 'Where is Tokyo?');
await tester.tap(find.text('Map'));
await settle(tester);
await pickOnMap(tester);
tester.widget<RegionMap>(find.byType(RegionMap)).onRegionTapped!('JP-13');
await settle(tester);
await tester.tap(find.byType(CloseButton));
await settle(tester);
expect(find.byType(RegionMap), findsNothing);
expect(find.text('Tap to pick the region on the map'), findsOneWidget);
});
}

View file

@ -19,7 +19,7 @@ void main() {
});
/// Shows the maps at a phone's size, anew unless [key] is the one shown;
/// what is picked lands in the list.
/// what is picked lands in the list, and shows as picked.
Future<List<String>> show(
WidgetTester tester, {
Key? key,
@ -34,6 +34,7 @@ void main() {
..devicePixelRatio = 1;
addTearDown(tester.view.reset);
final picked = <String>[];
final shown = key ?? UniqueKey();
await tester.pumpWidget(
MaterialApp(
theme: appTheme(Brightness.light),
@ -42,14 +43,19 @@ void main() {
home: Scaffold(
body: Padding(
padding: const EdgeInsets.all(16),
child: RegionMap(
key: key ?? UniqueKey(),
atlas: atlas,
countryTaps: countryTaps,
around: around,
right: right,
wrong: wrong,
onRegionTapped: readOnly ? null : picked.add,
child: StatefulBuilder(
builder: (context, setState) => RegionMap(
key: shown,
atlas: atlas,
countryTaps: countryTaps,
around: around,
selected: picked.lastOrNull,
right: right,
wrong: wrong,
onRegionTapped: readOnly
? null
: (code) => setState(() => picked.add(code)),
),
),
),
),
@ -96,11 +102,12 @@ void main() {
const tokyo = (139.69, 35.69);
testWidgets('Japan is picked in East Asia, and a chip opens its '
'prefectures in layers; Back goes up one', (tester) async {
testWidgets('Japan is picked in East Asia, and once it is, a chip opens '
'its prefectures in layers; Back goes up one', (tester) async {
final picked = await show(tester);
await choose(tester, 'East Asia');
expect(chip('Prefectures'), findsNothing);
await tapAt(tester, tokyo);
expect(picked, ['JP']);
@ -130,6 +137,11 @@ void main() {
await tester.tap(back('East Asia'));
await tester.pumpAndSettle();
expect(find.text('East Asia'), findsOneWidget);
// Osaka is within Japan; Seoul isn't.
expect(chip('Prefectures'), findsOneWidget);
await tapAt(tester, (126.98, 37.57));
expect(picked.last, 'KR');
expect(chip('Prefectures'), findsNothing);
await tester.tap(back('World'));
await tester.pumpAndSettle();
expect(chip('Europe'), findsOneWidget);