refactor(theme): the look comes from halkyon_ui
The theme, Noto Sans, the window sizes and the widgets every screen is built of move to halkyon_ui (halkyon_shared), pinned to a signed commit as the sync fork is, so Halkyon's other apps share them. Learn keeps its own colours (the FSRS ratings, a starred star) as LearnColors beside the theme, the CJK fonts with their licences, and its launch screen's word and icon. Nothing on screen changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
642c1c7e9f
commit
f43b92e4db
44 changed files with 451 additions and 4755 deletions
|
|
@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/profile/public_person.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/text_limits.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/auth/data/auth_gateway.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/auth/data/sign_in_addresses.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/auth/model/auth_status.dart';
|
||||
|
|
@ -17,6 +16,7 @@ import 'package:halkyon_learn_flutter/src/feature/settings/data/settings_reposit
|
|||
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_payload.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/tag/data/tag_repository.dart';
|
||||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
import '../support/fake_auth_gateway.dart';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/dependencies/dependencies_scope.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/dependencies/person_dependencies.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/dependencies/person_scope.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/sync/sync_service.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/auth/model/auth_status.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/card/data/card_deletions.dart';
|
||||
|
|
@ -132,7 +132,7 @@ void main() {
|
|||
DependenciesScope(
|
||||
dependencies: testDependencies(openPerson: (_) => open()),
|
||||
child: const MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: PersonScope(person: person, child: Text('Home')),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import 'dart:convert';
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_document.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_view.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_payload.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart';
|
||||
|
|
@ -246,7 +246,7 @@ void main() {
|
|||
]).node;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: RichContentView(
|
||||
content: Document(
|
||||
|
|
@ -286,7 +286,7 @@ void main() {
|
|||
|
||||
Future<void> pump(WidgetTester tester, Widget child) => tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(body: child),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
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/format_bar.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_view.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/scripts.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/content_languages.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ void main() {
|
|||
latest = content ?? RichContent.plain(text);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: ContentLanguages(
|
||||
languages: (front: language, back: 'en'),
|
||||
child: Scaffold(
|
||||
|
|
@ -226,7 +226,7 @@ void main() {
|
|||
'smaller', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: ListView(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
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/editor_clipboard.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/link.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
/// Content of one line of [runs], each a text and its marks.
|
||||
|
|
@ -80,7 +80,7 @@ void main() {
|
|||
final latest = [...contents];
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: Column(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_math_fork/flutter_math.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
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/math_view.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_document.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_view.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/app_theme.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/learn_theme.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
|
|
@ -47,8 +47,8 @@ void main() {
|
|||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: appTheme(Brightness.light),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
theme: learnTheme(Brightness.light),
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: SizedBox(
|
||||
height: 600,
|
||||
|
|
@ -208,8 +208,8 @@ void main() {
|
|||
Future<void> show(WidgetTester tester, RichContent content) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: appTheme(Brightness.light),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
theme: learnTheme(Brightness.light),
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(body: RichContentView(content: content)),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.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/l10n/app_languages.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
|
|
@ -10,7 +10,7 @@ void main() {
|
|||
'and bringing the selection into view comes to an end', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: ListView(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
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_view.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/ruby.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
|
|
@ -28,7 +28,7 @@ void main() {
|
|||
Future<void> show(WidgetTester tester, RichContent content) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: ListView(children: [RichContentView(content: content)]),
|
||||
),
|
||||
|
|
@ -152,7 +152,7 @@ void main() {
|
|||
var tapped = 0;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: ListView(
|
||||
children: [
|
||||
|
|
@ -198,7 +198,7 @@ void main() {
|
|||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(
|
||||
body: ListView(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
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_document.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_view.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/app_theme.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/learn_theme.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
|
|
@ -18,8 +18,8 @@ void main() {
|
|||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: appTheme(Brightness.light),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
theme: learnTheme(Brightness.light),
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(body: child),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
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/dependencies/dependencies_scope.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_document.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_view.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/app_theme.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/learn_theme.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
import '../../support/fake_youtube_videos.dart';
|
||||
|
|
@ -24,8 +24,8 @@ void main() {
|
|||
DependenciesScope(
|
||||
dependencies: testDependencies(videos: videos),
|
||||
child: MaterialApp(
|
||||
theme: appTheme(Brightness.light),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
theme: learnTheme(Brightness.light),
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
home: Scaffold(body: child),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/layout/window_size.dart';
|
||||
|
||||
void main() {
|
||||
test("Material 3's classes, by the window's width", () {
|
||||
expect(WindowSize.fromWidth(0), WindowSize.compact);
|
||||
expect(WindowSize.fromWidth(599.9), WindowSize.compact);
|
||||
expect(WindowSize.fromWidth(600), WindowSize.medium);
|
||||
expect(WindowSize.fromWidth(839.9), WindowSize.medium);
|
||||
expect(WindowSize.fromWidth(840), WindowSize.expanded);
|
||||
expect(WindowSize.fromWidth(1199.9), WindowSize.expanded);
|
||||
expect(WindowSize.fromWidth(1200), WindowSize.large);
|
||||
expect(WindowSize.fromWidth(1599.9), WindowSize.large);
|
||||
expect(WindowSize.fromWidth(1600), WindowSize.extraLarge);
|
||||
});
|
||||
|
||||
test('a rail from medium on, desktop layouts from expanded on', () {
|
||||
expect(WindowSize.compact.isAtLeastMedium, isFalse);
|
||||
expect(WindowSize.medium.isAtLeastMedium, isTrue);
|
||||
expect(WindowSize.medium.isAtLeastExpanded, isFalse);
|
||||
expect(WindowSize.expanded.isAtLeastExpanded, isTrue);
|
||||
expect(WindowSize.extraLarge.isAtLeastExpanded, isTrue);
|
||||
});
|
||||
}
|
||||
|
|
@ -2,11 +2,6 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/brand.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/palette_color.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/floating_navigation_bar.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/screen_tint.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/top_gradient.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';
|
||||
import 'package:halkyon_learn_flutter/src/feature/home/widget/activity_heatmap.dart';
|
||||
|
|
@ -15,6 +10,7 @@ import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_payload
|
|||
import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/widget/library_screen.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/widget/studyset_screen.dart';
|
||||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
import '../../support/fake_card_gateway.dart';
|
||||
|
|
|
|||
122
halkyon_learn_flutter/test/core/theme/cjk_fonts_test.dart
Normal file
122
halkyon_learn_flutter/test/core/theme/cjk_fonts_test.dart
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/cjk_fonts.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/learn_theme.dart';
|
||||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
/// Loads the bundled font [family] from [files], as the app does at start.
|
||||
Future<void> load(String family, List<String> files) async {
|
||||
final loader = FontLoader(family);
|
||||
for (final file in files) {
|
||||
loader.addFont(rootBundle.load(file));
|
||||
}
|
||||
await loader.load();
|
||||
}
|
||||
|
||||
/// How many pixels [text] inks in [family] at [weight]: heavier strokes ink
|
||||
/// more.
|
||||
Future<int> ink(String text, String family, FontWeight weight) async {
|
||||
final painter = TextPainter(
|
||||
text: TextSpan(
|
||||
text: text,
|
||||
style: TextStyle(
|
||||
fontFamily: family,
|
||||
fontSize: 40,
|
||||
fontWeight: weight,
|
||||
color: const Color(0xFF000000),
|
||||
),
|
||||
),
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout();
|
||||
final recorder = ui.PictureRecorder();
|
||||
painter.paint(Canvas(recorder), Offset.zero);
|
||||
final image = await recorder.endRecording().toImage(
|
||||
painter.width.ceil(),
|
||||
painter.height.ceil(),
|
||||
);
|
||||
final pixels = (await image.toByteData())!;
|
||||
var inked = 0;
|
||||
for (var alpha = 3; alpha < pixels.lengthInBytes; alpha += 4) {
|
||||
if (pixels.getUint8(alpha) > 128) {
|
||||
inked++;
|
||||
}
|
||||
}
|
||||
return inked;
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
test("the theme sets text in halkyon_ui's Noto Sans, with Noto Sans JP "
|
||||
'for what it lacks', () {
|
||||
for (final brightness in Brightness.values) {
|
||||
final style = learnTheme(brightness).textTheme.bodyLarge!;
|
||||
expect(style.fontFamily, 'packages/halkyon_ui/Noto Sans');
|
||||
expect(style.fontFamilyFallback, [
|
||||
'Noto Sans JP',
|
||||
'Noto Sans SC',
|
||||
'Noto Sans TC',
|
||||
'Noto Sans KR',
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
test('the app bundles every font the theme names', () async {
|
||||
final manifest = jsonDecode(
|
||||
await rootBundle.loadString('FontManifest.json'),
|
||||
) as List<dynamic>;
|
||||
final families = {
|
||||
for (final font in manifest.cast<Map<String, dynamic>>())
|
||||
font['family'] as String,
|
||||
};
|
||||
|
||||
expect(families, containsAll([appFontFamily, ...appFontFallback]));
|
||||
});
|
||||
|
||||
test('each bundled font draws every weight from its one file', () async {
|
||||
await load(appFontFamily, [
|
||||
'packages/halkyon_ui/assets/fonts/NotoSans-Variable.ttf',
|
||||
]);
|
||||
for (final region in ['JP', 'SC', 'TC', 'KR']) {
|
||||
await load('Noto Sans $region', [
|
||||
'assets/fonts/NotoSans$region-Variable.otf',
|
||||
]);
|
||||
}
|
||||
|
||||
for (final (family, text) in [
|
||||
(appFontFamily, 'Ἀθῆναι Halkyon'),
|
||||
('Noto Sans JP', '日本語のかな'),
|
||||
('Noto Sans SC', '我们说中文'),
|
||||
('Noto Sans TC', '我們說中文'),
|
||||
('Noto Sans KR', '한국어 공부'),
|
||||
]) {
|
||||
final regular = await ink(text, family, FontWeight.w400);
|
||||
final bold = await ink(text, family, FontWeight.w700);
|
||||
expect(bold, greaterThan(regular * 1.2), reason: family);
|
||||
}
|
||||
});
|
||||
|
||||
test("the fonts' licences join the licence list", () async {
|
||||
registerFontLicenses();
|
||||
registerCjkFontLicenses();
|
||||
|
||||
final packages = {
|
||||
await for (final entry in LicenseRegistry.licenses) ...entry.packages,
|
||||
};
|
||||
expect(
|
||||
packages,
|
||||
containsAll([
|
||||
'Noto Sans',
|
||||
'Noto Sans JP',
|
||||
'Noto Sans SC',
|
||||
'Noto Sans TC',
|
||||
'Noto Sans KR',
|
||||
]),
|
||||
);
|
||||
});
|
||||
}
|
||||
47
halkyon_learn_flutter/test/core/theme/learn_theme_test.dart
Normal file
47
halkyon_learn_flutter/test/core/theme/learn_theme_test.dart
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/learn_colors.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/learn_theme.dart';
|
||||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
/// WCAG's contrast ratio of two colours, from 1 (none) to 21.
|
||||
double _contrast(Color a, Color b) {
|
||||
final (lighter, darker) = (
|
||||
max(a.computeLuminance(), b.computeLuminance()),
|
||||
min(a.computeLuminance(), b.computeLuminance()),
|
||||
);
|
||||
return (lighter + 0.05) / (darker + 0.05);
|
||||
}
|
||||
|
||||
void main() {
|
||||
for (final brightness in Brightness.values) {
|
||||
test("$brightness: halkyon_ui's theme, with Learn's rating and starred "
|
||||
'colours beside its status colours', () {
|
||||
final theme = learnTheme(brightness);
|
||||
|
||||
expect(theme.colorScheme, appTheme(brightness).colorScheme);
|
||||
expect(theme.extras, isA<ThemeExtras>());
|
||||
expect(
|
||||
theme.learnColors,
|
||||
brightness == Brightness.light ? LearnColors.light : LearnColors.dark,
|
||||
);
|
||||
});
|
||||
|
||||
test('$brightness: a starred star stands out from the cards, as a '
|
||||
'graphic must (3 to 1)', () {
|
||||
final theme = learnTheme(brightness);
|
||||
|
||||
for (final surface in [
|
||||
theme.colorScheme.surface,
|
||||
theme.colorScheme.surfaceContainerLow,
|
||||
]) {
|
||||
expect(
|
||||
_contrast(theme.learnColors.starred, surface),
|
||||
greaterThanOrEqualTo(3),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/app_theme.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/brand.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/palette_color.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/theme_extras.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
/// WCAG's contrast ratio of two colours, from 1 (none) to 21.
|
||||
double _contrast(Color a, Color b) {
|
||||
final (lighter, darker) = (
|
||||
max(a.computeLuminance(), b.computeLuminance()),
|
||||
min(a.computeLuminance(), b.computeLuminance()),
|
||||
);
|
||||
return (lighter + 0.05) / (darker + 0.05);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('the picker palette', () {
|
||||
test('has the 20 colours content can be given', () {
|
||||
expect(PaletteColor.values, hasLength(20));
|
||||
});
|
||||
|
||||
for (final color in PaletteColor.values) {
|
||||
test(
|
||||
'${color.name}: its text colour is readable on its fill (WCAG AA)',
|
||||
() {
|
||||
expect(
|
||||
_contrast(color.foreground, color.background),
|
||||
greaterThanOrEqualTo(4.5),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
test(
|
||||
'finds a colour by its stored name, and nothing for an unknown one',
|
||||
() {
|
||||
expect(PaletteColor.byName('cobalt'), PaletteColor.cobalt);
|
||||
expect(PaletteColor.byName('ultraviolet'), isNull);
|
||||
expect(PaletteColor.byName(null), isNull);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('the theme', () {
|
||||
for (final brightness in Brightness.values) {
|
||||
test('$brightness: Material 3, with the status and rating colours', () {
|
||||
final theme = appTheme(brightness);
|
||||
|
||||
expect(theme.useMaterial3, isTrue);
|
||||
expect(theme.colorScheme.brightness, brightness);
|
||||
expect(theme.extras, isA<ThemeExtras>());
|
||||
});
|
||||
}
|
||||
|
||||
test('light: cobalt is the primary colour, copper the accent', () {
|
||||
final scheme = appTheme(Brightness.light).colorScheme;
|
||||
|
||||
expect(scheme.primary, Brand.primary);
|
||||
expect(scheme.tertiary, Brand.accent);
|
||||
});
|
||||
|
||||
test("dark: the primary colour's text stays readable", () {
|
||||
final scheme = appTheme(Brightness.dark).colorScheme;
|
||||
|
||||
expect(
|
||||
_contrast(scheme.onPrimary, scheme.primary),
|
||||
greaterThanOrEqualTo(4.5),
|
||||
);
|
||||
expect(
|
||||
_contrast(scheme.onSurface, scheme.surface),
|
||||
greaterThanOrEqualTo(4.5),
|
||||
);
|
||||
});
|
||||
|
||||
for (final brightness in Brightness.values) {
|
||||
test('$brightness: a starred star stands out from the cards, as a '
|
||||
'graphic must (3 to 1)', () {
|
||||
final theme = appTheme(brightness);
|
||||
|
||||
for (final surface in [
|
||||
theme.colorScheme.surface,
|
||||
theme.colorScheme.surfaceContainerLow,
|
||||
]) {
|
||||
expect(
|
||||
_contrast(theme.extras.starred, surface),
|
||||
greaterThanOrEqualTo(3),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/adaptive_sheet.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
/// Opens a sheet titled "New studyset" with [body] and a Create button, in
|
||||
/// a window [width] wide, with a status bar [statusBar] high on top.
|
||||
Future<void> open(
|
||||
WidgetTester tester, {
|
||||
required double width,
|
||||
Widget body = const Text('Body'),
|
||||
double statusBar = 0,
|
||||
bool busy = false,
|
||||
}) async {
|
||||
tester.view.physicalSize = Size(width, 900);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
tester.view.padding = FakeViewPadding(top: statusBar);
|
||||
tester.view.viewPadding = FakeViewPadding(top: statusBar);
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) => TextButton(
|
||||
onPressed: () => showAdaptiveSheet<void>(
|
||||
context,
|
||||
swipeable: !busy,
|
||||
builder: (context) => SheetScaffold(
|
||||
title: 'New studyset',
|
||||
busy: busy,
|
||||
body: body,
|
||||
footer: FilledButton(
|
||||
onPressed: () {},
|
||||
child: const Text('Create'),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Text('Open'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.text('Open'));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
testWidgets('is a bottom sheet below expanded windows', (tester) async {
|
||||
await open(tester, width: 839);
|
||||
|
||||
expect(find.byType(BottomSheet), findsOneWidget);
|
||||
expect(find.byType(Dialog), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('is a dialog from expanded windows on', (tester) async {
|
||||
await open(tester, width: 840);
|
||||
|
||||
expect(find.byType(Dialog), findsOneWidget);
|
||||
expect(find.byType(BottomSheet), findsNothing);
|
||||
});
|
||||
|
||||
for (final width in [400.0, 1200.0]) {
|
||||
testWidgets('keeps its close button and footer in view above a long body '
|
||||
'(${width.round()} wide)', (tester) async {
|
||||
await open(
|
||||
tester,
|
||||
width: width,
|
||||
body: Column(
|
||||
children: [for (var i = 0; i < 80; i++) Text('Line $i')],
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byTooltip('Close').hitTestable(), findsOneWidget);
|
||||
expect(find.text('Create').hitTestable(), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
testWidgets('stays below the status bar with the keyboard open', (
|
||||
tester,
|
||||
) async {
|
||||
await open(
|
||||
tester,
|
||||
width: 400,
|
||||
statusBar: 48,
|
||||
body: Column(
|
||||
children: [for (var i = 0; i < 80; i++) Text('Line $i')],
|
||||
),
|
||||
);
|
||||
|
||||
tester.view.viewInsets = const FakeViewPadding(bottom: 400);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(tester.getTopLeft(find.byType(BottomSheet)).dy, 48);
|
||||
expect(find.byTooltip('Close').hitTestable(), findsOneWidget);
|
||||
expect(find.text('Create').hitTestable(), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('closes with its close button', (tester) async {
|
||||
await open(tester, width: 400);
|
||||
|
||||
await tester.tap(find.byTooltip('Close'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('New studyset'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('while busy, its close button is off and back keeps it open', (
|
||||
tester,
|
||||
) async {
|
||||
await open(tester, width: 400, busy: true);
|
||||
|
||||
expect(
|
||||
tester
|
||||
.widget<IconButton>(
|
||||
find.ancestor(
|
||||
of: find.byTooltip('Close'),
|
||||
matching: find.byType(IconButton),
|
||||
),
|
||||
)
|
||||
.onPressed,
|
||||
isNull,
|
||||
);
|
||||
await tester.binding.handlePopRoute();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('New studyset'), findsOneWidget);
|
||||
});
|
||||
|
||||
group('a body longer than the sheet', () {
|
||||
final tall = Column(
|
||||
children: [for (var i = 0; i < 40; i++) const Text('Line')],
|
||||
);
|
||||
Finder below() => find.byKey(SheetScaffold.moreBelowKey);
|
||||
Finder above() => find.byKey(SheetScaffold.moreAboveKey);
|
||||
|
||||
testWidgets('shows a line above the buttons while more lies below, and '
|
||||
'one under the title while more lies above', (tester) async {
|
||||
// As a dialog: a modal bottom sheet takes a test's drag itself.
|
||||
await open(tester, width: 1000, body: tall);
|
||||
|
||||
expect(below(), findsOneWidget);
|
||||
expect(above(), findsNothing);
|
||||
|
||||
await tester.drag(
|
||||
find.byType(SingleChildScrollView),
|
||||
const Offset(0, -300),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(below(), findsOneWidget);
|
||||
expect(above(), findsOneWidget);
|
||||
expect(
|
||||
tester
|
||||
.state<ScrollableState>(
|
||||
find.descendant(
|
||||
of: find.byType(SingleChildScrollView),
|
||||
matching: find.byType(Scrollable),
|
||||
),
|
||||
)
|
||||
.position
|
||||
.pixels,
|
||||
greaterThan(0),
|
||||
reason: 'the line coming keeps where the body was scrolled to',
|
||||
);
|
||||
|
||||
await tester.drag(
|
||||
find.byType(SingleChildScrollView),
|
||||
const Offset(0, -5000),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(below(), findsNothing);
|
||||
expect(above(), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('has a scrollbar, always shown on the desktop', (tester) async {
|
||||
debugDefaultTargetPlatformOverride = TargetPlatform.linux;
|
||||
addTearDown(() => debugDefaultTargetPlatformOverride = null);
|
||||
await open(tester, width: 1000, body: tall);
|
||||
|
||||
final scrollbar = tester.widget<Scrollbar>(find.byType(Scrollbar));
|
||||
expect(scrollbar.thumbVisibility, isTrue);
|
||||
debugDefaultTargetPlatformOverride = null;
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('a body that fits shows no lines', (tester) async {
|
||||
await open(tester, width: 400);
|
||||
|
||||
expect(find.byKey(SheetScaffold.moreBelowKey), findsNothing);
|
||||
expect(find.byKey(SheetScaffold.moreAboveKey), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets("the body keeps clear of the scroll view's edges, where it is "
|
||||
'cut and the scrollbar runs', (tester) async {
|
||||
for (final width in [400.0, 1000.0]) {
|
||||
await open(
|
||||
tester,
|
||||
width: width,
|
||||
body: const TextField(
|
||||
decoration: InputDecoration(border: OutlineInputBorder()),
|
||||
),
|
||||
);
|
||||
|
||||
final scrolling = tester.getRect(find.byType(SingleChildScrollView));
|
||||
final field = tester.getRect(find.byType(TextField));
|
||||
expect(field.left - scrolling.left, greaterThanOrEqualTo(16));
|
||||
expect(scrolling.right - field.right, greaterThanOrEqualTo(16));
|
||||
// The title and the button stay in line with the body.
|
||||
expect(tester.getTopLeft(find.text('New studyset')).dx, field.left);
|
||||
expect(tester.getTopRight(find.byType(FilledButton)).dx, field.right);
|
||||
await tester.tap(find.byTooltip('Close'));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/l10n/app_languages.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/app_launch_screen.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('shows the kingfisher, and "Halkyon" over "Learn", read out '
|
||||
"as the app's name", (tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
localizationsDelegates: appLocalizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: AppLaunchScreen(),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(Image), findsOneWidget);
|
||||
final brand = tester.getRect(find.text('Halkyon'));
|
||||
final product = tester.getRect(find.text('Learn'));
|
||||
expect(product.top, greaterThanOrEqualTo(brand.bottom - 1));
|
||||
expect(product.center.dx, moreOrLessEquals(brand.center.dx));
|
||||
expect(find.bySemanticsLabel('Halkyon Learn'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:expressive_loading_indicator/expressive_loading_indicator.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/theme/app_theme.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/app_loading_indicator.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("pulled down, it refreshes with the app's spinner, Material 3 "
|
||||
"Expressive's, not Flutter's older one", (tester) async {
|
||||
final refreshing = Completer<void>();
|
||||
var refreshes = 0;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: appTheme(Brightness.light),
|
||||
home: Scaffold(
|
||||
body: AppRefreshIndicator(
|
||||
onRefresh: () {
|
||||
refreshes++;
|
||||
return refreshing.future;
|
||||
},
|
||||
child: ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: const [Text('Japanese')],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(find.byType(ExpressiveLoadingIndicator), findsNothing);
|
||||
|
||||
await tester.fling(find.text('Japanese'), const Offset(0, 400), 1000);
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 300));
|
||||
expect(refreshes, 1);
|
||||
expect(find.byType(ExpressiveLoadingIndicator), findsOneWidget);
|
||||
expect(find.byType(CircularProgressIndicator), findsNothing);
|
||||
|
||||
refreshing.complete();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(ExpressiveLoadingIndicator), findsNothing);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/count_stepper.dart';
|
||||
|
||||
void main() {
|
||||
test('steps go to the next multiple of the step, never below the first', () {
|
||||
expect(stepUp(12, 5, max: 100), 15);
|
||||
expect(stepUp(15, 5, max: 100), 20);
|
||||
expect(stepUp(98, 5, max: 100), 100);
|
||||
expect(stepDown(12, 5), 10);
|
||||
expect(stepDown(15, 5), 10);
|
||||
expect(stepDown(7, 5), 5);
|
||||
expect(canStepDown(5, 5), isFalse);
|
||||
expect(canStepDown(6, 5), isTrue);
|
||||
expect(stepUp(1, 25, max: 1000), 25);
|
||||
expect(stepDown(230, 25), 225);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/app_loading_indicator.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/widget/found_by_id.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
late StreamController<List<String>> items;
|
||||
|
||||
setUp(() => items = StreamController());
|
||||
tearDown(() => items.close());
|
||||
|
||||
/// Opens the screen of the item [id] over a first screen.
|
||||
Future<void> open(WidgetTester tester, String id) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Builder(
|
||||
builder: (context) => TextButton(
|
||||
onPressed: () => Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (context) => FoundById<String>(
|
||||
id: id,
|
||||
items: () => items.stream,
|
||||
idOf: (item) => item,
|
||||
builder: (item, items) =>
|
||||
Scaffold(body: Text('Item $item of ${items.length}')),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Text('Open'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.text('Open'));
|
||||
// Through the opening transition; the spinner never settles.
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
}
|
||||
|
||||
testWidgets('shows a spinner until the list arrives, then the item', (
|
||||
tester,
|
||||
) async {
|
||||
await open(tester, 'a');
|
||||
expect(find.byType(AppLoadingIndicator), findsOneWidget);
|
||||
|
||||
items.add(['a', 'b']);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('Item a of 2'), findsOneWidget);
|
||||
expect(find.byType(AppLoadingIndicator), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('says that an item missing from the list no longer exists', (
|
||||
tester,
|
||||
) async {
|
||||
await open(tester, 'c');
|
||||
|
||||
items.add(['a', 'b']);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.textContaining('no longer exists'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('says so once the item goes while its screen is open', (
|
||||
tester,
|
||||
) async {
|
||||
await open(tester, 'a');
|
||||
items.add(['a']);
|
||||
await tester.pump();
|
||||
|
||||
// Deleted on another device, say.
|
||||
items.add([]);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('Item a of 1'), findsNothing);
|
||||
expect(find.textContaining('no longer exists'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('a screen that closes as its item goes keeps showing the item '
|
||||
'on its way out', (tester) async {
|
||||
await open(tester, 'a');
|
||||
items.add(['a']);
|
||||
await tester.pump();
|
||||
|
||||
// As when the screen deleted its item and closes.
|
||||
Navigator.of(tester.element(find.text('Item a of 1'))).pop();
|
||||
items.add([]);
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
expect(find.text('Item a of 1'), findsOneWidget);
|
||||
expect(find.textContaining('no longer exists'), findsNothing);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Open'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue